From 8257347a09e57667ca4865baa547aeb9918768ff Mon Sep 17 00:00:00 2001 From: Hamcha Date: Tue, 16 Jul 2019 16:43:29 +0200 Subject: [PATCH] Actually get the feeds --- package.json | 2 ++ src/components/EventList/EventCard.vue | 22 +++++++++++++++++++ src/components/EventList/ListView.vue | 27 +++++++++++++++++++++++ src/store/actions.ts | 29 ++++++++++++++++++++++--- src/store/feed.ts | 8 +++++++ src/store/getters.ts | 6 +++--- src/store/mutations.ts | 15 ++++++++++--- src/store/types.ts | 17 +++++++++------ src/utils.ts | 13 +++++++++++ src/views/Home.vue | 9 ++++++-- yarn.lock | 30 +++++++++++++++++++++++++- 11 files changed, 160 insertions(+), 18 deletions(-) create mode 100644 src/components/EventList/EventCard.vue create mode 100644 src/components/EventList/ListView.vue create mode 100644 src/store/feed.ts create mode 100644 src/utils.ts diff --git a/package.json b/package.json index a03ce6e..4f907cd 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "postcss-nested": "^4.1.2", "postcss-smart-import": "^0.7.6", "register-service-worker": "^1.6.2", + "rss-parser": "^3.7.2", "tailwindcss": "^1.0.4", "vue": "^2.6.10", "vue-class-component": "^7.0.2", @@ -22,6 +23,7 @@ "vuex-class": "^0.3.2" }, "devDependencies": { + "@types/xml2js": "^0.4.4", "@vue/cli-plugin-babel": "^3.8.0", "@vue/cli-plugin-eslint": "^3.8.0", "@vue/cli-plugin-pwa": "^3.8.0", diff --git a/src/components/EventList/EventCard.vue b/src/components/EventList/EventCard.vue new file mode 100644 index 0000000..70a74c3 --- /dev/null +++ b/src/components/EventList/EventCard.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/components/EventList/ListView.vue b/src/components/EventList/ListView.vue new file mode 100644 index 0000000..5623a8a --- /dev/null +++ b/src/components/EventList/ListView.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/store/actions.ts b/src/store/actions.ts index 949171a..bd8ca70 100644 --- a/src/store/actions.ts +++ b/src/store/actions.ts @@ -1,9 +1,12 @@ import { ActionTree } from "vuex"; -import { AppState } from "./types"; +import { AppState, EventFeed, FeedEvent } from "./types"; +import { toEvent } from "./feed"; +import Parser from "rss-parser"; +import { mustArray } from "@/utils"; const actions: ActionTree = { // Add one or more sources - addSources({ commit, dispatch }, sources: EventSource[]) { + addSources({ commit, dispatch }, sources: EventFeed[]) { // Commit to state immediately commit("appendSources", sources); // Start fetching from each new source @@ -12,7 +15,27 @@ const actions: ActionTree = { // Fetch events from a source url async fetchFromSource({ commit }, url: string) { - //TODO + try { + const parser = new Parser(); + const feed = await parser.parseURL(url); + // Parse events + const events: FeedEvent[] = mustArray(feed.items) + .map(toEvent) + .map(x => ({ + source: url, + data: x + })); + commit("setSourceStatus", { + url, + info: { title: feed.title, description: feed.description }, + status: { fetched: true, events } + }); + } catch (e) { + commit("setSourceStatus", { + url, + status: { fetched: true, error: e } + }); + } } }; diff --git a/src/store/feed.ts b/src/store/feed.ts new file mode 100644 index 0000000..6185885 --- /dev/null +++ b/src/store/feed.ts @@ -0,0 +1,8 @@ +import { FeedEvent, FeedEventData } from "./types"; +import { Item } from "rss-parser"; + +export function toEvent(item: Item): FeedEventData { + return { + guid: item.guid || item.link || item.title || Math.random().toString(32) + }; +} diff --git a/src/store/getters.ts b/src/store/getters.ts index 3ca1892..15dd778 100644 --- a/src/store/getters.ts +++ b/src/store/getters.ts @@ -1,15 +1,15 @@ import { GetterTree } from "vuex"; -import { AppState, Event, EventSource } from "./types"; +import { AppState, FeedEvent, EventFeed } from "./types"; const getters: GetterTree = { - events(state): Event[] { + events(state): FeedEvent[] { return Object.values(state.status) .filter(x => x.fetched && x.error == null) .map(x => x.events) .flat(); }, - sources(state): EventSource[] { + sources(state): EventFeed[] { return state.sources; } }; diff --git a/src/store/mutations.ts b/src/store/mutations.ts index 51affd6..cc1015f 100644 --- a/src/store/mutations.ts +++ b/src/store/mutations.ts @@ -1,8 +1,8 @@ import { MutationTree } from "vuex"; -import { AppState, FetchStatus, EventSource } from "./types"; +import { AppState, FetchStatus, EventFeed, FeedInfo } from "./types"; const mutations: MutationTree = { - appendSources(state, payload: EventSource[]) { + appendSources(state, payload: EventFeed[]) { // Add sources to list state.sources = state.sources.concat(payload); @@ -12,8 +12,17 @@ const mutations: MutationTree = { }); }, - setSourceStatus(state, payload: { url: string; status: FetchStatus }) { + setSourceStatus( + state, + payload: { url: string; info?: FeedInfo; status: FetchStatus } + ) { state.status[payload.url] = payload.status; + if (payload.info) { + let source = state.sources.find(x => x.url == payload.url); + if (source) { + source.info = payload.info; + } + } } }; diff --git a/src/store/types.ts b/src/store/types.ts index cf304e5..5da4b36 100644 --- a/src/store/types.ts +++ b/src/store/types.ts @@ -1,21 +1,26 @@ import { Dict } from "@/types"; export interface AppState { - sources: EventSource[]; + sources: EventFeed[]; status: Dict; } -export interface EventSource { +export interface EventFeed { url: string; + info?: FeedInfo; } -export interface Event { +export interface FeedInfo { + title: string; +} + +export interface FeedEvent { source: string; // Source URL - data: EventData; + data: FeedEventData; } -export interface EventData { - //TODO +export interface FeedEventData { + guid: string; } export interface FetchStatus { diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..a268b91 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,13 @@ +export function must(val?: T): T { + if (val) { + return val; + } + throw "must assertion failed"; +} + +export function mustArray(val?: T[]): T[] { + if (val) { + return val; + } + return []; +} diff --git a/src/views/Home.vue b/src/views/Home.vue index 22b3c6e..2a24091 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -1,12 +1,17 @@ diff --git a/yarn.lock b/yarn.lock index 1ebd4dd..502ccaf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -774,6 +774,13 @@ resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.9.tgz#a67287861c928ebf4159a908d1fb1a2a34d4097a" integrity sha512-p8zp5xqkly3g4cCmo2mKOHI9+Z/kObmDj0BmjbDDJQlgDTiEGTbm17MEwTAusV6XceCy+bNw9q/ZHXHyKo3zkg== +"@types/xml2js@^0.4.4": + version "0.4.4" + resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.4.4.tgz#2093d94359a201806d997dccefc80153db311c66" + integrity sha512-O6Xgai01b9PB3IGA0lRIp1Ex3JBcxGDhdO0n3NIIpCyDOAjxcIGQFmkvgJpP8anTrthxOUQjBfLdRRi0Zn/TXA== + dependencies: + "@types/node" "*" + "@typescript-eslint/eslint-plugin@^1.1.0": version "1.11.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.11.0.tgz#870f752c520db04db6d3668af7479026a6f2fb9a" @@ -7149,6 +7156,14 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rss-parser@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/rss-parser/-/rss-parser-3.7.2.tgz#9f5b7d4944d4f7a190b469e31a8353aedb17c052" + integrity sha512-kx0VIFelgwBk5qA4n32U6cx40anAU7TwlRXjyxLDFgMlg8/UcJ64x+Hj5oRX1Kjos+OeFGOmnd5YXH5ES+bmzg== + dependencies: + entities "^1.1.1" + xml2js "^0.4.19" + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -7199,7 +7214,7 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.2.4, sax@~1.2.4: +sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -8834,6 +8849,19 @@ ws@^6.0.0: dependencies: async-limiter "~1.0.0" +xml2js@^0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= + xtend@^4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"