diff --git a/src/containers/settings/groups-container.tsx b/src/containers/settings/groups-container.tsx index 9368e58..90ffcbe 100644 --- a/src/containers/settings/groups-container.tsx +++ b/src/containers/settings/groups-container.tsx @@ -3,7 +3,8 @@ import { connect } from "react-redux" import { createSelector } from "reselect" import { RootState } from "../../scripts/reducer" import GroupsTab from "../../components/settings/groups" -import { createSourceGroup, SourceGroup, updateSourceGroup, addSourceToGroup, deleteSourceGroup, removeSourceFromGroup, reorderSourceGroups } from "../../scripts/models/page" +import { createSourceGroup, SourceGroup, updateSourceGroup, addSourceToGroup, + deleteSourceGroup, removeSourceFromGroup, reorderSourceGroups } from "../../scripts/models/page" const getSources = (state: RootState) => state.sources const getGroups = (state: RootState) => state.page.sourceGroups diff --git a/src/scripts/models/app.ts b/src/scripts/models/app.ts index c0a9fdf..189b903 100644 --- a/src/scripts/models/app.ts +++ b/src/scripts/models/app.ts @@ -157,7 +157,7 @@ export function appReducer( fetchingItems: false, settings: { ...state.settings, - saving: false + saving: action.batch } } } diff --git a/src/scripts/models/page.ts b/src/scripts/models/page.ts index ba097cc..1b70deb 100644 --- a/src/scripts/models/page.ts +++ b/src/scripts/models/page.ts @@ -1,7 +1,7 @@ -import { RSSSource, SourceActionTypes, INIT_SOURCES, ADD_SOURCE, DELETE_SOURCE, addSource } from "./source" +import fs = require("fs") +import { SourceActionTypes, ADD_SOURCE, DELETE_SOURCE, addSource } from "./source" import { ALL, SOURCE } from "./feed" import { ActionStatus, AppThunk, domParser, AppDispatch } from "../utils" -import fs = require("fs") import { saveSettings } from "./app" const GROUPS_STORE_KEY = "sourceGroups" @@ -204,11 +204,14 @@ export function reorderSourceGroups(groups: SourceGroup[]): AppThunk { } async function outlineToSource(dispatch: AppDispatch, outline: Element): Promise { - let url = outline.getAttribute("xmlUrl").trim() + let url = outline.getAttribute("xmlUrl") let name = outline.getAttribute("text") || outline.getAttribute("name") if (url) { - let sid = await dispatch(addSource(url, name)) - return sid || null + try { + return await dispatch(addSource(url.trim(), name, true)) + } catch (e) { + return null + } } else { return null } @@ -221,9 +224,13 @@ export function importOPML(path: string): AppThunk { console.log(err) } else { dispatch(saveSettings()) - let successes: number, failures: number - let doc = domParser.parseFromString(data, "text/xml") - for (let el of doc.body.children) { + let successes: number = 0, failures: number = 0 + let doc = domParser.parseFromString(data, "text/xml").getElementsByTagName("body") + if (doc.length == 0) { + dispatch(saveSettings()) + return + } + for (let el of doc[0].children) { if (el.getAttribute("type") === "rss") { let sid = await outlineToSource(dispatch, el) if (sid === null) failures += 1 @@ -231,14 +238,19 @@ export function importOPML(path: string): AppThunk { } else if (el.hasAttribute("text") || el.hasAttribute("title")) { let groupName = el.getAttribute("text") || el.getAttribute("title") let gid = dispatch(createSourceGroup(groupName)) - let sid = await outlineToSource(dispatch, el) - if (sid === null) failures += 1 - else { - successes += 1 - dispatch(addSourceToGroup(gid, sid)) + for (let child of el.children) { + let sid = await outlineToSource(dispatch, child) + if (sid === null) { + failures += 1 + } else { + successes += 1 + dispatch(addSourceToGroup(gid, sid)) + } } } } + console.log(failures, successes) + dispatch(saveSettings()) } }) } diff --git a/src/scripts/models/source.ts b/src/scripts/models/source.ts index ab52f5f..c93b951 100644 --- a/src/scripts/models/source.ts +++ b/src/scripts/models/source.ts @@ -22,17 +22,21 @@ export class RSSSource { async fetchMetaData(parser: Parser) { let feed = await parser.parseURL(this.url) - if (!this.name) this.name = feed.title.trim() + if (!this.name && feed.title) this.name = feed.title.trim() this.description = feed.description let domain = this.url.split("/").slice(0, 3).join("/") - let 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: string = null + try { + f = await faviconPromise(domain) + } finally { + 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 + } + return feed } - return feed } private static checkItem(source: RSSSource, item: Parser.Item, db: Nedb): Promise { @@ -92,6 +96,7 @@ interface InitSourcesAction { interface AddSourceAction { type: typeof ADD_SOURCE status: ActionStatus + batch: boolean source?: RSSSource err? } @@ -148,34 +153,37 @@ export function initSources(): AppThunk> { } } -export function addSourceRequest(): SourceActionTypes { +export function addSourceRequest(batch: boolean): SourceActionTypes { return { type: ADD_SOURCE, + batch: batch, status: ActionStatus.Request } } -export function addSourceSuccess(source: RSSSource): SourceActionTypes { +export function addSourceSuccess(source: RSSSource, batch: boolean): SourceActionTypes { return { type: ADD_SOURCE, + batch: batch, status: ActionStatus.Success, source: source } } -export function addSourceFailure(err): SourceActionTypes { +export function addSourceFailure(err, batch: boolean): SourceActionTypes { return { type: ADD_SOURCE, + batch: batch, status: ActionStatus.Failure, err: err } } -export function addSource(url: string, name: string = null): AppThunk> { +export function addSource(url: string, name: string = null, batch = false): AppThunk> { return (dispatch, getState) => { let app = getState().app if (app.sourceInit && !app.fetchingItems) { - dispatch(addSourceRequest()) + dispatch(addSourceRequest(batch)) let source = new RSSSource(url, name) return source.fetchMetaData(rssParser) .then(feed => { @@ -186,7 +194,7 @@ export function addSource(url: string, name: string = null): AppThunk insertItems(items)) .then(items => { @@ -200,7 +208,8 @@ export function addSource(url: string, name: string = null): AppThunk { console.log(e) - dispatch(addSourceFailure(e)) + dispatch(addSourceFailure(e, batch)) + return new Promise((_, reject) => { reject(e) }) }) } return new Promise((_, reject) => { reject("Sources not initialized or fetching items.") })