Compare commits
No commits in common. "main" and "v0.0.1" have entirely different histories.
14 changed files with 283 additions and 403 deletions
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
* @troylusty
|
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "cargo"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
groups:
|
||||||
|
dev-dependencies:
|
||||||
|
patterns:
|
||||||
|
- "*"
|
|
@ -1,4 +1,4 @@
|
||||||
name: Release
|
name: Rust
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
@ -19,10 +19,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: https://github.com/dtolnay/rust-toolchain@stable
|
- name: Build release
|
||||||
- run: cargo build --release
|
run: cargo build --release
|
||||||
|
|
||||||
- name: Upload release assets
|
- name: Upload release assets
|
||||||
uses: https://gitea.com/actions/gitea-release-action@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
files: ${{ env.BIN_NAME }}
|
files: ${{ env.BIN_NAME }}
|
135
Cargo.lock
generated
135
Cargo.lock
generated
|
@ -81,12 +81,6 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.97"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atom_syndication"
|
name = "atom_syndication"
|
||||||
version = "0.12.6"
|
version = "0.12.6"
|
||||||
|
@ -153,9 +147,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.16"
|
version = "1.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
|
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
@ -168,23 +162,23 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.40"
|
version = "0.4.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
"android-tzdata",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-link",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.31"
|
version = "4.5.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
|
checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
@ -192,9 +186,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.31"
|
version = "4.5.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
|
checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
@ -204,9 +198,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.28"
|
version = "4.5.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
|
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -226,6 +220,15 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "3.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console"
|
name = "console"
|
||||||
version = "0.15.10"
|
version = "0.15.10"
|
||||||
|
@ -341,6 +344,15 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "emojis"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99e1f1df1f181f2539bac8bf027d31ca5ffbf9e559e3f2d09413b9107b5c02f4"
|
||||||
|
dependencies = [
|
||||||
|
"phf",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encode_unicode"
|
name = "encode_unicode"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -837,9 +849,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indicatif"
|
name = "indicatif"
|
||||||
version = "0.17.11"
|
version = "0.17.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
|
checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console",
|
"console",
|
||||||
"number_prefix",
|
"number_prefix",
|
||||||
|
@ -987,9 +999,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.70"
|
version = "0.10.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6"
|
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
@ -1019,9 +1031,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.105"
|
version = "0.9.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc"
|
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -1031,16 +1043,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packard"
|
name = "packard"
|
||||||
version = "0.0.4"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"colored",
|
||||||
|
"emojis",
|
||||||
"futures",
|
"futures",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rss",
|
"rss",
|
||||||
"serde",
|
"serde",
|
||||||
|
"terminal-link",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
"xdg",
|
"xdg",
|
||||||
|
@ -1052,6 +1066,24 @@ version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
@ -1150,23 +1182,24 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.17.13"
|
version = "0.17.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee"
|
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"libc",
|
"libc",
|
||||||
|
"spin",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rss"
|
name = "rss"
|
||||||
version = "2.0.12"
|
version = "2.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2107738f003660f0a91f56fd3e3bd3ab5d918b2ddaf1e1ec2136fb1c46f71bf"
|
checksum = "531af70fce504d369cf42ac0a9645f5a62a8ea9265de71cfa25087e9f6080c7c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atom_syndication",
|
"atom_syndication",
|
||||||
"derive_builder",
|
"derive_builder",
|
||||||
|
@ -1272,18 +1305,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.218"
|
version = "1.0.217"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
|
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.218"
|
version = "1.0.217"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
|
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1329,6 +1362,12 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
@ -1354,6 +1393,12 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -1438,6 +1483,12 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "terminal-link"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "253bcead4f3aa96243b0f8fa46f9010e87ca23bd5d0c723d474ff1d2417bbdf8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
|
@ -1510,9 +1561,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.20"
|
version = "0.8.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
|
@ -1531,9 +1582,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.23"
|
version = "0.22.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee"
|
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -1758,12 +1809,6 @@ dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-link"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-registry"
|
name = "windows-registry"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -1878,9 +1923,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.1"
|
version = "0.6.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f"
|
checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -1,22 +1,24 @@
|
||||||
[package]
|
[package]
|
||||||
name = "packard"
|
name = "packard"
|
||||||
version = "0.0.4"
|
version = "0.0.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A terminal based feed checker."
|
description = "A terminal based feed checker."
|
||||||
authors = ["Troy Lusty <hello@troylusty.com>"]
|
authors = ["Troy Lusty <hello@troylusty.com>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4.40"
|
chrono = "0.4.39"
|
||||||
clap = { version = "4.5.31", features = ["derive"] }
|
clap = { version = "4.5.26", features = ["derive"] }
|
||||||
reqwest = "0.12.12"
|
reqwest = "0.12.12"
|
||||||
rss = "2.0.12"
|
rss = "2.0.11"
|
||||||
serde = { version = "1.0.218", features = ["derive"] }
|
serde = { version = "1.0.217", features = ["derive"] }
|
||||||
tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread"] }
|
||||||
toml = "0.8.20"
|
toml = "0.8.19"
|
||||||
xdg = "2.5.2"
|
xdg = "2.5.2"
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
indicatif = "0.17.11"
|
indicatif = "0.17.9"
|
||||||
anyhow = "1.0.97"
|
colored = "3.0.0"
|
||||||
|
terminal-link = "0.1.0"
|
||||||
|
emojis = "0.6.4"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 0
|
opt-level = 0
|
||||||
|
|
30
README.md
30
README.md
|
@ -1,30 +1,10 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>️📰 Packard</h1>
|
<h1>️📰 Packard</h1>
|
||||||
<img alt="Release" src="https://img.shields.io/gitea/v/release/troy/packard?gitea_url=https%3A%2F%2Fcode.troylusty.com">
|
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/troylusty/packard">
|
||||||
<h5>Packard is a simple RSS aggregator meant to allow you to take a quick glance at what's occurring in topics you care about.</h5>
|
<h5>Packard is a simple RSS aggregator meant to allow you to take a quick glance at what's occurring in topics you care about.</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
This is my first attempt at making something with Rust so that I may learn alongside creating something that I personally find useful.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
On NixOS you can install Packard by including it as an input in flake.nix, then adding it to your system packages.
|
|
||||||
|
|
||||||
```nix
|
|
||||||
inputs = {
|
|
||||||
packard.url = "git+https://code.troylusty.com/troy/packard";
|
|
||||||
};
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
environment.systemPackages = {
|
|
||||||
inputs.packard.packages."${pkgs.system}".default
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, the [latest release](https://github.com/troylusty/packard/releases/latest) binary is available.
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
@ -68,4 +48,8 @@ news = [
|
||||||
|
|
||||||
After running Packard with your configured settings, the parsed results can be opened in your default browser however your terminal allows for opening URLs. For example the keybind for this with [Foot](https://codeberg.org/dnkl/foot#urls) is `ctrl` + `shift` + `o`.
|
After running Packard with your configured settings, the parsed results can be opened in your default browser however your terminal allows for opening URLs. For example the keybind for this with [Foot](https://codeberg.org/dnkl/foot#urls) is `ctrl` + `shift` + `o`.
|
||||||
|
|
||||||
Currently no keyboard interaction is implemented. To get around this you can pipe the output of Packard into a tool like `less` like so: `packard -c 12 -l news -s 3 | less`.
|
Currently no keyboard interaction is implemented. To get around this you can pipe the output of Packard into a tool like `less` like so: `packard -c 12 -l news -s 3 | less`. Be aware, this will remove any text formatting that has been applied.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
For anyone who may or may not look at this, I am very new to Rust with this being my first project making use of it. So expect mistakes.
|
||||||
|
|
BIN
demo/demo.gif
BIN
demo/demo.gif
Binary file not shown.
Before Width: | Height: | Size: 761 KiB |
|
@ -1,19 +0,0 @@
|
||||||
Output demo.gif
|
|
||||||
|
|
||||||
Require packard
|
|
||||||
|
|
||||||
Set Shell "zsh"
|
|
||||||
Set FontSize 32
|
|
||||||
Set Width 1200
|
|
||||||
Set Height 600
|
|
||||||
|
|
||||||
Type@250ms "packard" Sleep 500ms
|
|
||||||
Hide Type " -c 48 -l news" Show Sleep 500ms
|
|
||||||
Type@200ms " | less" Sleep 500ms Enter
|
|
||||||
Sleep 3s
|
|
||||||
PageDown@50ms 1
|
|
||||||
Sleep 1s
|
|
||||||
PageDown@50ms 2
|
|
||||||
Sleep 1s
|
|
||||||
PageUp@50ms 3
|
|
||||||
Sleep 3s
|
|
61
flake.lock
generated
61
flake.lock
generated
|
@ -1,61 +0,0 @@
|
||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1731533236,
|
|
||||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1736701207,
|
|
||||||
"narHash": "sha256-jG/+MvjVY7SlTakzZ2fJ5dC3V1PrKKrUEOEE30jrOKA=",
|
|
||||||
"owner": "nixos",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "ed4a395ea001367c1f13d34b1e01aa10290f67d6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nixos",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
41
flake.nix
41
flake.nix
|
@ -1,41 +0,0 @@
|
||||||
{
|
|
||||||
description = "Packard is a simple RSS aggregator meant to allow you to take a quick glance at what's occurring in topics you care about.";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = {
|
|
||||||
self,
|
|
||||||
nixpkgs,
|
|
||||||
flake-utils,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
flake-utils.lib.eachDefaultSystem (system: let
|
|
||||||
pkgs = import nixpkgs {inherit system;};
|
|
||||||
in {
|
|
||||||
packages = {
|
|
||||||
packard = let
|
|
||||||
manifest = (pkgs.lib.importTOML ./Cargo.toml).package;
|
|
||||||
in
|
|
||||||
pkgs.rustPlatform.buildRustPackage {
|
|
||||||
pname = manifest.name;
|
|
||||||
version = manifest.version;
|
|
||||||
|
|
||||||
cargoLock.lockFile = ./Cargo.lock;
|
|
||||||
|
|
||||||
src = pkgs.lib.cleanSource ./.;
|
|
||||||
|
|
||||||
nativeBuildInputs = [pkgs.pkg-config];
|
|
||||||
buildInputs = [pkgs.openssl];
|
|
||||||
};
|
|
||||||
default = self.packages.${system}.packard;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
// {
|
|
||||||
overlays.default = final: prev: {
|
|
||||||
inherit (self.packages.${final.system}) packard;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
use clap::Parser;
|
|
||||||
use serde::Deserialize;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fs;
|
|
||||||
use xdg::BaseDirectories;
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
|
||||||
#[command(author, version, about, long_about = None)]
|
|
||||||
pub struct Cli {
|
|
||||||
#[arg(short, long)]
|
|
||||||
pub verbose: bool,
|
|
||||||
#[arg(short, long)]
|
|
||||||
pub count: Option<u8>,
|
|
||||||
#[arg(short = 'l', long)]
|
|
||||||
pub selected_list: Option<String>,
|
|
||||||
#[arg(short, long)]
|
|
||||||
pub skip_amount: Option<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct Config {
|
|
||||||
pub count: Option<u8>,
|
|
||||||
pub skip_amount: Option<u8>,
|
|
||||||
pub selected_list: Option<String>,
|
|
||||||
pub lists: HashMap<String, Vec<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_cli() -> Cli {
|
|
||||||
let args = Cli::parse();
|
|
||||||
args
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn collate_values(args: Cli, config: &Config) -> (u8, u8, String) {
|
|
||||||
if args.verbose {
|
|
||||||
println!("{:?}", args);
|
|
||||||
println!("Selected list: {:?}", config.selected_list);
|
|
||||||
println!("Items: {:?}", config.lists);
|
|
||||||
}
|
|
||||||
|
|
||||||
let count: u8 = if args.count.is_some() {
|
|
||||||
args.count.expect("Count flag wrong?")
|
|
||||||
} else if config.count.is_some() {
|
|
||||||
config.count.expect("Unable to use count value from config")
|
|
||||||
} else {
|
|
||||||
8
|
|
||||||
};
|
|
||||||
|
|
||||||
let skip_amount: u8 = if args.skip_amount.is_some() {
|
|
||||||
args.skip_amount.expect("Skip amount flag wrong?")
|
|
||||||
} else if config.skip_amount.is_some() {
|
|
||||||
config
|
|
||||||
.skip_amount
|
|
||||||
.expect("Unable to use skip amount value from config")
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
let list: String = if args.selected_list.is_some() {
|
|
||||||
args.selected_list
|
|
||||||
.clone()
|
|
||||||
.expect("Error getting selected list from flag")
|
|
||||||
} else if config.selected_list.is_some() {
|
|
||||||
config
|
|
||||||
.selected_list
|
|
||||||
.clone()
|
|
||||||
.expect("Need to specify a selected list")
|
|
||||||
} else {
|
|
||||||
panic!("Need to set selected list")
|
|
||||||
};
|
|
||||||
|
|
||||||
(count, skip_amount, list)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate_config() -> Config {
|
|
||||||
let xdg_dirs = BaseDirectories::new().expect("Failed to get XDG directories");
|
|
||||||
let config_path = xdg_dirs
|
|
||||||
.place_config_file("packard/config.toml")
|
|
||||||
.expect("Failed to determine config file path");
|
|
||||||
|
|
||||||
if !config_path.exists() {
|
|
||||||
eprintln!("Configuration file not found at {:?}", config_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
let config_content = fs::read_to_string(&config_path).expect("Failed to read config file");
|
|
||||||
let config: Config = toml::de::from_str(&config_content).expect("Failed to parse TOML");
|
|
||||||
config
|
|
||||||
}
|
|
68
src/data.rs
68
src/data.rs
|
@ -1,68 +0,0 @@
|
||||||
use anyhow::{Context, Result};
|
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use futures::future::join_all;
|
|
||||||
use indicatif::ProgressBar;
|
|
||||||
use reqwest::get;
|
|
||||||
use rss::Channel;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct FeedItem {
|
|
||||||
pub title: String,
|
|
||||||
pub description: String,
|
|
||||||
pub link: String,
|
|
||||||
pub pub_date: DateTime<Utc>,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn fetch_rss(url: &str, pb: &ProgressBar) -> Result<Channel> {
|
|
||||||
let response = get(url)
|
|
||||||
.await
|
|
||||||
.context("Failed to send request")?
|
|
||||||
.text()
|
|
||||||
.await
|
|
||||||
.context("Failed to read response text")?;
|
|
||||||
let channel = Channel::read_from(response.as_bytes()).context("Failed to parse RSS feed")?;
|
|
||||||
pb.inc(1);
|
|
||||||
pb.set_message(format!("Processing: {}", channel.title));
|
|
||||||
Ok(channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_feed(channel: &Channel) -> Vec<FeedItem> {
|
|
||||||
channel
|
|
||||||
.items()
|
|
||||||
.iter()
|
|
||||||
.map(|item| FeedItem {
|
|
||||||
title: item.title().unwrap_or("No title").to_string(),
|
|
||||||
description: item.description().unwrap_or("No description").to_string(),
|
|
||||||
link: item.link().unwrap_or("No link").to_string(),
|
|
||||||
pub_date: item
|
|
||||||
.pub_date()
|
|
||||||
.and_then(|date_str| DateTime::parse_from_rfc2822(date_str).ok())
|
|
||||||
.map(|dt| dt.with_timezone(&Utc))
|
|
||||||
.unwrap_or_else(|| Utc::now()),
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run_tasks(
|
|
||||||
sources: Vec<String>,
|
|
||||||
count: u8,
|
|
||||||
skip: u8,
|
|
||||||
pb: &ProgressBar,
|
|
||||||
) -> Vec<FeedItem> {
|
|
||||||
let fetch_futures: Vec<_> = sources.iter().map(|url| fetch_rss(url, &pb)).collect();
|
|
||||||
|
|
||||||
let channels = join_all(fetch_futures).await;
|
|
||||||
|
|
||||||
let mut all_items = Vec::new();
|
|
||||||
|
|
||||||
for channel in channels.into_iter().filter_map(Result::ok) {
|
|
||||||
let feed_items = parse_feed(&channel);
|
|
||||||
all_items.extend(feed_items);
|
|
||||||
}
|
|
||||||
|
|
||||||
all_items.sort_by(|a, b| b.pub_date.cmp(&a.pub_date));
|
|
||||||
all_items.truncate((count + skip).into());
|
|
||||||
let removed_items = all_items.split_off(skip.into());
|
|
||||||
|
|
||||||
removed_items
|
|
||||||
}
|
|
182
src/main.rs
182
src/main.rs
|
@ -1,34 +1,174 @@
|
||||||
use indicatif::ProgressStyle;
|
use chrono::{DateTime, Utc};
|
||||||
use tokio::io;
|
use clap::Parser;
|
||||||
|
use colored::Colorize;
|
||||||
|
use emojis;
|
||||||
|
use futures::future::join_all;
|
||||||
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
|
use reqwest::get;
|
||||||
|
use rss::Channel;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs;
|
||||||
|
use terminal_link::Link;
|
||||||
|
use tokio;
|
||||||
|
use toml;
|
||||||
|
use xdg::BaseDirectories;
|
||||||
|
|
||||||
mod config;
|
#[derive(Parser, Debug)]
|
||||||
mod data;
|
#[command(author, version, about, long_about = None)]
|
||||||
mod utils;
|
struct Cli {
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool,
|
||||||
|
#[arg(short, long)]
|
||||||
|
count: Option<u8>,
|
||||||
|
#[arg(short = 'l', long)]
|
||||||
|
selected_list: Option<String>,
|
||||||
|
#[arg(short, long)]
|
||||||
|
skip_amount: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct Config {
|
||||||
|
count: Option<u8>,
|
||||||
|
skip_amount: Option<u8>,
|
||||||
|
selected_list: Option<String>,
|
||||||
|
lists: HashMap<String, Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct FeedItem {
|
||||||
|
title: String,
|
||||||
|
description: String,
|
||||||
|
link: String,
|
||||||
|
pub_date: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_rss(url: &str, pb: &ProgressBar) -> Result<Channel, Box<dyn Error>> {
|
||||||
|
let response = get(url).await?.text().await?;
|
||||||
|
let channel = Channel::read_from(response.as_bytes())?;
|
||||||
|
pb.inc(1);
|
||||||
|
pb.set_message(format!("Processing: {}", channel.title));
|
||||||
|
Ok(channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_feed(channel: &Channel) -> Vec<FeedItem> {
|
||||||
|
channel
|
||||||
|
.items()
|
||||||
|
.iter()
|
||||||
|
.map(|item| FeedItem {
|
||||||
|
title: item.title().unwrap_or("No title").to_string(),
|
||||||
|
description: item.description().unwrap_or("No description").to_string(),
|
||||||
|
link: item.link().unwrap_or("No link").to_string(),
|
||||||
|
pub_date: item
|
||||||
|
.pub_date()
|
||||||
|
.and_then(|date_str| DateTime::parse_from_rfc2822(date_str).ok())
|
||||||
|
.map(|dt| dt.with_timezone(&Utc))
|
||||||
|
.unwrap_or_else(|| Utc::now()),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_config() -> Config {
|
||||||
|
let xdg_dirs = BaseDirectories::new().expect("Failed to get XDG directories");
|
||||||
|
let config_path = xdg_dirs
|
||||||
|
.place_config_file("packard/config.toml")
|
||||||
|
.expect("Failed to determine config file path");
|
||||||
|
|
||||||
|
if !config_path.exists() {
|
||||||
|
eprintln!("Configuration file not found at {:?}", config_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let config_content = fs::read_to_string(&config_path).expect("Failed to read config file");
|
||||||
|
let config: Config = toml::de::from_str(&config_content).expect("Failed to parse TOML");
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trim_chars(input: &str) -> String {
|
||||||
|
let trimmed: String = input.chars().take(256).collect();
|
||||||
|
|
||||||
|
if trimmed.len() < input.len() {
|
||||||
|
format!("{}...", trimmed)
|
||||||
|
} else {
|
||||||
|
trimmed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_tasks(sources: Vec<String>, count: u8, skip: u8, pb: &ProgressBar) -> Vec<FeedItem> {
|
||||||
|
let fetch_futures: Vec<_> = sources.iter().map(|url| fetch_rss(url, &pb)).collect();
|
||||||
|
|
||||||
|
let channels = join_all(fetch_futures).await;
|
||||||
|
|
||||||
|
let mut all_items = Vec::new();
|
||||||
|
|
||||||
|
for channel in channels.into_iter().filter_map(Result::ok) {
|
||||||
|
let feed_items = parse_feed(&channel);
|
||||||
|
all_items.extend(feed_items);
|
||||||
|
}
|
||||||
|
|
||||||
|
all_items.sort_by(|a, b| b.pub_date.cmp(&a.pub_date));
|
||||||
|
all_items.truncate((count + skip).into());
|
||||||
|
let removed_items = all_items.split_off(skip.into());
|
||||||
|
|
||||||
|
removed_items
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), io::Error> {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let config = config::validate_config();
|
let config = validate_config();
|
||||||
let args = config::parse_cli();
|
let args = Cli::parse();
|
||||||
let (count, skip_amount, list) = config::collate_values(args, &config);
|
|
||||||
|
if args.verbose {
|
||||||
|
println!("{:?}", args);
|
||||||
|
println!("Selected list: {:?}", config.selected_list);
|
||||||
|
println!("Items: {:?}", config.lists);
|
||||||
|
}
|
||||||
|
|
||||||
|
let count: u8 = if args.count.is_some() {
|
||||||
|
args.count.expect("Count flag wrong?")
|
||||||
|
} else if config.count.is_some() {
|
||||||
|
config.count.expect("Unable to use count value from config")
|
||||||
|
} else {
|
||||||
|
8
|
||||||
|
};
|
||||||
|
|
||||||
|
let skip_amount: u8 = if args.skip_amount.is_some() {
|
||||||
|
args.skip_amount.expect("Skip amount flag wrong?")
|
||||||
|
} else if config.skip_amount.is_some() {
|
||||||
|
config
|
||||||
|
.skip_amount
|
||||||
|
.expect("Unable to use skip amount value from config")
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let list: String = if args.selected_list.is_some() {
|
||||||
|
args.selected_list
|
||||||
|
.expect("Error getting selected list from flag")
|
||||||
|
} else if config.selected_list.is_some() {
|
||||||
|
config
|
||||||
|
.selected_list
|
||||||
|
.expect("Need to specify a selected list")
|
||||||
|
} else {
|
||||||
|
panic!("Need to set selected list")
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(values) = config.lists.get(&list) {
|
if let Some(values) = config.lists.get(&list) {
|
||||||
let pb = indicatif::ProgressBar::new(
|
let pb = indicatif::ProgressBar::new(12);
|
||||||
values
|
pb.set_style(
|
||||||
.len()
|
ProgressStyle::with_template("[{elapsed}] {bar:40.green/black} {msg}").unwrap(),
|
||||||
.try_into()
|
|
||||||
.expect("Could not convert list length"),
|
|
||||||
);
|
);
|
||||||
pb.set_style(ProgressStyle::with_template("{wide_bar} {percent}% {msg}").unwrap());
|
|
||||||
let all_items = data::run_tasks(values.to_vec(), count, skip_amount, &pb).await;
|
let all_items = run_tasks(values.to_vec(), count, skip_amount, &pb).await;
|
||||||
pb.finish_and_clear();
|
pb.finish_and_clear();
|
||||||
|
|
||||||
for item in all_items {
|
for item in all_items {
|
||||||
println!(
|
println!(
|
||||||
"\x1b[1m>\x1b[0m \x1b[1;32m\x1b]8;;{}\x1b\\{}\x1b]8;;\x1b\\\x1b[0m\n\x1b[3m\x1b[2m{}\x1b[0m\n\x1b[2m{}\x1b[0m\n",
|
"{} {}\n{}\n{}\n",
|
||||||
item.link,
|
emojis::get_by_shortcode("newspaper").unwrap(),
|
||||||
item.title,
|
Link::new(&item.title, &item.link),
|
||||||
utils::trim_chars(&utils::remove_html_tags(&item.description)),
|
trim_chars(&item.description).dimmed().italic(),
|
||||||
item.pub_date.to_string()
|
item.pub_date.to_string().dimmed().bold()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
26
src/utils.rs
26
src/utils.rs
|
@ -1,26 +0,0 @@
|
||||||
pub fn trim_chars(input: &str) -> String {
|
|
||||||
let trimmed: String = input.chars().take(256).collect();
|
|
||||||
|
|
||||||
if trimmed.len() < input.len() {
|
|
||||||
format!("{}...", trimmed)
|
|
||||||
} else {
|
|
||||||
trimmed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_html_tags(input: &str) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
let mut in_tag = false;
|
|
||||||
|
|
||||||
for c in input.chars() {
|
|
||||||
if c == '<' {
|
|
||||||
in_tag = true;
|
|
||||||
} else if c == '>' {
|
|
||||||
in_tag = false;
|
|
||||||
} else if !in_tag {
|
|
||||||
result.push(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue