-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
346 additions
and
19 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
Oops, something went wrong.