Skip to content

Commit

Permalink
Finish command-line MVP
Browse files Browse the repository at this point in the history
  • Loading branch information
rgardner committed Mar 1, 2020
1 parent f508988 commit d86d105
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 19 deletions.
80 changes: 80 additions & 0 deletions app/pocket_cleaner/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions app/pocket_cleaner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
chrono = "0.4.10"
actix-rt = "1.0.0"
actix-web = { version = "2.0.0", features = ["openssl"] }
url = "2.1.1"
serde = "1.0.104"
anyhow = "1.0.26"
chrono = "0.4.10"
env_logger = "0.7.1"
log = "0.4.8"
serde = "1.0.104"
serde_json = "1.0.48"
actix-rt = "1.0.0"
thiserror = "1.0.11"
url = "2.1.1"
35 changes: 35 additions & 0 deletions app/pocket_cleaner/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Pocket Cleaner

Finds items from your Pocket library that are relevant to trending news.

```sh
$ pocket_cleaner
1. amirrajan/survivingtheappstore (Why: Real Madrid)
2. CppCon 2017: Nicolas Guillemot “Design Patterns for Low-Level Real-Time Rendering” (Why: Real Madrid)
3. I Am Legend author Richard Matheson dies (Why: Mikaela Spielberg)
4. Record and share your terminal sessions, the right way. (Why: Mikaela Spielberg)
5. Firefox (1982) (Why: Carrie Symonds)
6. Navy Drone Lands on Aircraft Carrier (Why: Carrie Symonds)
7. Hillary Clinton on the Sanctity of Protecting Classified Information (Why: Drake)
8. EFF’s Game Plan for Ending Global Mass Surveillance (Why: Drake)
9. Drawing with Ants: Generative Art with Ant Colony Optimization Algorithms (Why: El Clasico 2020)
10. All 50+ Adobe apps explained in 10 minutes (Why: El Clasico 2020)
```

## Getting Started

Set the following environment variables:

- `POCKET_CLEANER_CONSUMER_KEY`
- Create a Pocket app on the [Pocket Developer
Portal](https://getpocket.com/developer/apps/)
- `POCKET_TEMP_USER_ACCESS_TOKEN`
- This will go away soon, but for now, manually use the [Pocket Authentication API](https://getpocket.com/developer/docs/authentication) to obtain your user access token.

```sh
export POCKET_CLEANER_CONSUMER_KEY="<TODO>"
export POCKET_TEMP_USER_ACCESS_TOKEN="<TODO>"
```

Then, run `cargo run` to build and run Pocket Cleaner to obtain
items from your Pocket list that are relevant to trending news.
13 changes: 13 additions & 0 deletions app/pocket_cleaner/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//! A module for working with Pocket Cleaner errors.

use thiserror::Error;

#[derive(Error, Debug)]
pub enum PocketCleanerError {
#[error("faulty logic: {0}")]
Logic(String),
#[error("unknown error: {0}")]
Unknown(String),
}

pub type Result<T> = std::result::Result<T, PocketCleanerError>;
61 changes: 56 additions & 5 deletions app/pocket_cleaner/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,66 @@
//! Surfaces items from your [Pocket](https://getpocket.com) library based on
//! trending headlines.

use crate::trends::{Geo, TrendFinder};
#![deny(
clippy::all,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unused_import_braces,
unused_qualifications
)]

use std::env;

use anyhow::{Context, Result};
use env_logger::Env;

use crate::{
pocket::PocketManager,
trends::{Geo, TrendFinder},
};

mod error;
mod pocket;
mod trends;

static POCKET_CONSUMER_KEY_ENV_VAR: &str = "POCKET_CLEANER_CONSUMER_KEY";
static POCKET_USER_ACCESS_TOKEN: &str = "POCKET_TEMP_USER_ACCESS_TOKEN";

fn get_pocket_consumer_key() -> Result<String> {
let key = POCKET_CONSUMER_KEY_ENV_VAR;
let value = env::var(key).with_context(|| format!("missing app config env var: {}", key))?;
Ok(value)
}

async fn try_main() -> Result<()> {
env_logger::from_env(Env::default().default_filter_or("warn")).init();

let trend_finder = TrendFinder::new();
let trends = trend_finder.daily_trends(&Geo("US".into())).await?;

let pocket_consumer_key = get_pocket_consumer_key()?;
let pocket_manager = PocketManager::new(pocket_consumer_key);
let user_pocket = pocket_manager.for_user(&env::var(POCKET_USER_ACCESS_TOKEN)?);

let mut items = Vec::new();
for trend in trends[..5].iter() {
let mut relevant_items = user_pocket.get_items(&trend.name()).await?;
items.extend(relevant_items.drain(..5).map(|i| (trend.name(), i)));
}

for (i, item) in items.iter().enumerate() {
println!("{} {} (Why: {})", i, item.1.title(), item.0);
}

Ok(())
}

#[actix_rt::main]
async fn main() {
let trend_finder = TrendFinder::new();
let trends = trend_finder.daily_trends(&Geo("US".into())).await.unwrap();
for (i, trend) in trends.iter().enumerate() {
println!("{}. {}", i, trend.name());
if let Err(e) = try_main().await {
eprintln!("{}", e);
}
}

0 comments on commit d86d105

Please sign in to comment.