├── .dockerignore ├── .gitignore ├── .vscode └── settings.json ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── app ├── .prettierrc ├── App.tsx ├── FeedForm.tsx ├── components │ ├── FeedLinkOutput.tsx │ ├── FeedPreview.tsx │ ├── FeedPreviewItem.tsx │ └── Footer.tsx ├── constants.ts ├── index.html ├── index.tsx └── regex_rs.ts ├── favicon.ico ├── img └── screenshot.png ├── package-lock.json ├── package.json ├── src ├── cors.rs ├── feed.rs ├── main.rs └── routes.rs ├── tsconfig.json ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js /.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | node_modules 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | 5 | # dependencies 6 | /node_modules 7 | /.pnp 8 | .pnp.js 9 | 10 | # testing 11 | /coverage 12 | 13 | # production 14 | /build 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | bundle.js 27 | *.wasm 28 | ./dist 29 | dist 30 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust.clippy_preference": "on" 3 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rssfilter" 3 | version = "0.1.0" 4 | authors = ["Benjamin Congdon "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | rss = { version = "*", features = ["from_url"] } 9 | rocket = "0.4.0" 10 | regex = "1" 11 | reqwest = "0.9.18" 12 | atom_syndication = "0.6.0" 13 | failure = "0.1.5" 14 | serde = "1.0.92" 15 | 16 | 17 | [dependencies.rocket_contrib] 18 | version = "0.4.1" 19 | default-features = false 20 | features = ["json"] 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:jessie AS builder 2 | 3 | RUN apt-get update && apt-get install -y curl build-essential libssl-dev pkg-config 4 | 5 | # Install rust 6 | RUN curl https://sh.rustup.rs/ -sSf | \ 7 | sh -s -- -y --default-toolchain nightly-2019-10-29 8 | 9 | ENV PATH="/root/.cargo/bin:${PATH}" 10 | 11 | ADD . ./ 12 | 13 | RUN cargo build --release 14 | 15 | FROM debian:jessie 16 | 17 | RUN apt-get update && apt-get install -y libssl-dev ca-certificates && rm -rf /var/lib/apt/lists/* 18 | 19 | COPY --from=builder \ 20 | /target/release/rssfilter \ 21 | /usr/local/bin/ 22 | 23 | WORKDIR /root 24 | CMD ROCKET_PORT=$PORT /usr/local/bin/rssfilter 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ben Congdon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | docker: 2 | docker build -t gcr.io/rssfilter/rssfilter . 3 | docker-upload: 4 | gcloud docker -- push gcr.io/rssfilter/rssfilter 5 | 6 | cloud-run: docker docker-upload 7 | 8 | clean: 9 | cargo clean 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

RSSFilter

2 |

3 | 4 | License: MIT 5 | 6 | 7 | Twitter: BenRCongdon 8 | 9 |

10 | 11 | > Like email filters, but for RSS feeds. 12 | 13 | ### 🌎 [Live Version](https://rssfilter.netlify.app/) 14 | 15 | ### 🏠 [Project Homepage](https://github.com/bcongdon/rssfilter#readme) 16 | 17 | ## Installation 18 | 19 | (Note: You must have [npm](https://www.npmjs.com/get-npm) and [cargo](https://rustup.rs/) installed.) 20 | 21 | 1. `git clone https://github.com/bcongdon/rssfilter && cd rssfilter` 22 | 2. Install frontend dependencies: `npm install` 23 | 3. Install backend dependencies: `cargo build` 24 | 25 | ## Usage 26 | 27 | ### Backend 28 | 29 | ```sh 30 | cargo run 31 | ``` 32 | 33 | ### Frontend 34 | 35 | ```sh 36 | npm run start 37 | ``` 38 | 39 | ## Screenshot 40 | 41 | ![screenshot](img/screenshot.png) 42 | 43 | ## Deploying to Google Cloud Run 44 | 45 | 1. Build the docker image: 46 | 47 | `docker build -t gcr.io/$PROJECT_ID/rssfilter .` 48 | 49 | 2. Upload to the GCP container image registry: 50 | 51 | `gcloud docker -- push gcr.io/$PROJECT_ID/rssfilter` 52 | 53 | 3. Deploy to Cloud Run: 54 | 55 | `TODO` 56 | 57 | ## Author 58 | 59 | 👤 **Benjamin Congdon** 60 | 61 | - Twitter: [@BenRCongdon](https://twitter.com/benrcongdon) 62 | - Github: [@bcongdon](https://github.com/bcongdon) 63 | 64 | ## 🤝 Contributing 65 | 66 | Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/bcongdon/rssfilter/issues). 67 | 68 | **Guidelines:** 69 | 70 | - Make sure that any frontend changes are linted with `npm run lint` 71 | - Make sure that any backend changes pass clippy checks (`cargo clippy`), and are properly formatted with `rustfmt`. 72 | 73 | ## Show your support 74 | 75 | Give a ⭐️ if this project helped you! 76 | 77 | ## Asset Attribution 78 | 79 | - Favicon is RSS by Rafaël Massé from the Noun Project 80 | 81 | ## 📝 License 82 | 83 | Copyright © 2019 [Benjamin Congdon](https://github.com/bcongdon).
84 | This project is [MIT](https://github.com/bcongdon/rssfilter/blob/master/LICENSE) licensed. 85 | -------------------------------------------------------------------------------- /app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "all", 4 | "tabWidth": 2, 5 | "semi": true, 6 | "singleQuote": true 7 | } 8 | -------------------------------------------------------------------------------- /app/App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Container, Header, Icon, Segment } from 'semantic-ui-react'; 3 | import { FeedForm, FeedFormValues } from './FeedForm'; 4 | import Footer from './components/Footer'; 5 | import FeedPreview from './components/FeedPreview'; 6 | import FeedLinkOutput from './components/FeedLinkOutput'; 7 | import * as QueryString from 'query-string'; 8 | 9 | import { baseURL } from './constants'; 10 | 11 | interface AppState { 12 | feedFormValues?: FeedFormValues; 13 | } 14 | 15 | export default class App extends React.Component<{}, AppState> { 16 | state: Readonly = { 17 | feedFormValues: null, 18 | }; 19 | 20 | onFormSubmit = (formValues: FeedFormValues) => { 21 | this.setState({ feedFormValues: formValues }); 22 | }; 23 | 24 | getFilterQueryString(): string { 25 | if (!this.state.feedFormValues) { 26 | return ''; 27 | } 28 | const { 29 | feedUrl, 30 | titleReject, 31 | titleAccept, 32 | authorAccept, 33 | authorReject, 34 | urlReject, 35 | urlAccept, 36 | } = this.state.feedFormValues; 37 | let query: any = { 38 | url: feedUrl, 39 | title_reject: titleReject, 40 | title_allow: titleAccept, 41 | author_reject: authorReject, 42 | author_allow: authorAccept, 43 | url_allow: urlAccept, 44 | url_reject: urlReject, 45 | }; 46 | Object.keys(query).forEach(key => !query[key] && delete query[key]); 47 | const queryString = QueryString.stringify(query); 48 | return queryString; 49 | } 50 | 51 | getFilterFeedURL(): string { 52 | return `${baseURL}/feed?${this.getFilterQueryString()}`; 53 | } 54 | 55 | getPreviewFeedURL(): string { 56 | return `${baseURL}/preview_feed?${this.getFilterQueryString()}`; 57 | } 58 | 59 | render() { 60 | const filterUrl = this.getFilterFeedURL(); 61 | const feedOutput = 62 | this.state.feedFormValues && this.state.feedFormValues.feedUrl ? ( 63 | 64 | 65 | 66 | 67 | ) : null; 68 | return ( 69 | 70 |
71 | 72 | RSS Filter 73 | 74 | RSSFilter is a simple web service that lets you filter articles out of RSS feeds. 75 | 76 | It's like email inbox rules, but for RSS feeds. 77 |
78 | 79 | 80 | 81 | {feedOutput} 82 |
83 |