Compare commits

...

28 commits

Author SHA1 Message Date
a087d27333
Release 3.3.4 2025-06-27 23:25:24 +02:00
42f46b33fd
Remaining Fixes 2025-06-27 23:24:44 +02:00
857c5040c3
Various Fixes + V3.3.3 2025-06-27 20:05:30 +02:00
b710b958f4
Release 3.3.2 2025-06-27 19:45:08 +02:00
2fac2fb7b4
Piefed API compat 2025-06-27 19:44:42 +02:00
f3bb504cfd
Release 3.3.1 2025-06-14 20:52:15 +02:00
42aff098bd
Login Delay 2025-06-14 20:52:05 +02:00
204d413779
Release 3.3.0 2025-06-14 20:21:36 +02:00
10111ff612
Change API Version from Lemmy v3 to Piefed Alpha 2025-06-14 20:21:23 +02:00
13954f26aa
Release 3.2.2 2025-04-22 13:33:23 +02:00
3abfaf55c1
Syntax Fix 2025-04-22 13:33:12 +02:00
da4220e027
Iterate over all returned posts from API rather than only the first one since pins stay at the top 2025-04-22 13:27:32 +02:00
3b5e65b350
Release 3.2.1 - fix 2025-03-25 21:11:44 +01:00
041590a559
Release 3.2.0 2024-10-22 16:15:19 +02:00
d6f883f890
Bump API version 2024-10-22 16:14:46 +02:00
b07420e0bd Merge pull request 'Bump forgejo-release to v2' () from actions-update into main
Reviewed-on: https://forgejo.neshweb.net///Neshura/aob-lemmy-bot/pulls/26
2024-08-06 12:23:26 +00:00
0fc71f0a7d Bump forgejo-release to v2 2024-08-06 12:19:37 +00:00
2ae6468ad8
Release 3.1.0 2024-07-15 22:15:49 +02:00
2ecfe88cb9
Update to 0.19.5 and include optional thumbnail 2024-07-15 22:15:31 +02:00
7dcc7bfee2
Release 3.0.3 2024-05-08 16:34:48 +02:00
94d8a4e673
Add Timeout to Status Ping HTTP Request 2024-05-08 16:34:32 +02:00
1b585eab7e
Release 3.0.2 2024-05-07 23:50:14 +02:00
b6f5c38e4a
Overhaul Error handling (Option instead of Result<T, ()> + Logging changes 2024-05-07 23:49:55 +02:00
5d708bdb82
Release 3.0.1 2024-05-07 22:50:22 +02:00
6a8c1662f0
Fix enum problems in config 2024-05-07 22:50:12 +02:00
e02cd900ed
Release 3.0.0 2024-05-07 22:35:15 +02:00
32ea83a7bb
Release Candidate 3.0.0-rc.2 2024-05-07 22:30:02 +02:00
4297860b9e
Legacy fixes for async traits 2024-05-07 22:29:48 +02:00
14 changed files with 861 additions and 480 deletions

View file

@ -137,7 +137,7 @@ jobs:
run: rm release_blobs/build.env
-
name: Release New Version
uses: actions/forgejo-release@v1
uses: actions/forgejo-release@v2
with:
direction: upload
url: https://forgejo.neshweb.net

603
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "addr2line"
@ -17,15 +17,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
@ -43,12 +34,11 @@ dependencies = [
[[package]]
name = "aob-lemmy-bot"
version = "3.0.0-rc.1"
version = "3.3.4"
dependencies = [
"async-trait",
"chrono",
"confy",
"lemmy_api_common",
"lemmy_db_schema",
"log",
"notify",
"once_cell",
@ -56,7 +46,9 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"strum_macros 0.26.2",
"serde_with",
"strum",
"strum_macros",
"systemd-journal-logger",
"tokio",
"toml",
@ -65,9 +57,9 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.77"
version = "0.1.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [
"proc-macro2",
"quote",
@ -95,12 +87,6 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.21.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
[[package]]
name = "base64"
version = "0.22.1"
@ -148,9 +134,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
@ -158,7 +144,7 @@ dependencies = [
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets 0.48.5",
"windows-targets 0.52.0",
]
[[package]]
@ -270,6 +256,17 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "encoding_rs"
version = "0.8.33"
@ -279,26 +276,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "enum-map"
version = "2.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9"
dependencies = [
"enum-map-derive",
]
[[package]]
name = "enum-map-derive"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@ -384,48 +361,36 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-io"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
[[package]]
name = "futures-macro"
version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
[[package]]
name = "futures-sink"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "futures-task"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-util"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
@ -436,15 +401,13 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.11"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
@ -486,9 +449,9 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "heck"
version = "0.4.1"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
@ -621,6 +584,124 @@ dependencies = [
"cc",
]
[[package]]
name = "icu_collections"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locid"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_locid_transform"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
dependencies = [
"displaydoc",
"icu_locid",
"icu_locid_transform_data",
"icu_provider",
"tinystr",
"zerovec",
]
[[package]]
name = "icu_locid_transform_data"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
[[package]]
name = "icu_normalizer"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
dependencies = [
"displaydoc",
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"utf16_iter",
"utf8_iter",
"write16",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
[[package]]
name = "icu_properties"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
dependencies = [
"displaydoc",
"icu_collections",
"icu_locid_transform",
"icu_properties_data",
"icu_provider",
"tinystr",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
[[package]]
name = "icu_provider"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
dependencies = [
"displaydoc",
"icu_locid",
"icu_provider_macros",
"stable_deref_trait",
"tinystr",
"writeable",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_provider_macros"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -629,12 +710,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.5.0"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
dependencies = [
"unicode-bidi",
"unicode-normalization",
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]]
@ -726,85 +818,11 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lemmy_api_common"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17366fcde90b07f4e5a8fefa62378fe348424ba79c8e9fb3ddc63ef76d687493"
dependencies = [
"chrono",
"enum-map",
"getrandom",
"lemmy_db_schema",
"lemmy_db_views",
"lemmy_db_views_actor",
"lemmy_db_views_moderator",
"regex",
"serde",
"serde_with",
"url",
]
[[package]]
name = "lemmy_db_schema"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e2d9a0c6f8f3df4664f9479ceca138ee6217b89653bafb753a498cabc5f3ab5"
dependencies = [
"async-trait",
"chrono",
"futures-util",
"serde",
"serde_with",
"strum",
"strum_macros 0.25.3",
"tracing",
"typed-builder",
"url",
"uuid",
]
[[package]]
name = "lemmy_db_views"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02659eb474ab54da6296d4edb5a974c0affa5cfcf8a2fa31bb52793dedef9d5a"
dependencies = [
"lemmy_db_schema",
"serde",
"serde_with",
]
[[package]]
name = "lemmy_db_views_actor"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5187730858dc808b5cf06aadbb1d1f8ca360d4ed3c375e5606e63be4c9e24e06"
dependencies = [
"chrono",
"lemmy_db_schema",
"serde",
"serde_with",
"strum",
"strum_macros 0.25.3",
]
[[package]]
name = "lemmy_db_views_moderator"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18f6fab36e1dcadc043b81c5916044ee65219d837f5d221a908296f9c55f3872"
dependencies = [
"lemmy_db_schema",
"serde",
"serde_with",
]
[[package]]
name = "libc"
version = "0.2.151"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libredox"
@ -823,6 +841,12 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]]
name = "litemap"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
[[package]]
name = "log"
version = "0.4.20"
@ -902,6 +926,12 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.17"
@ -1074,42 +1104,13 @@ dependencies = [
"thiserror",
]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "reqwest"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
dependencies = [
"base64 0.22.1",
"base64",
"bytes",
"encoding_rs",
"futures-channel",
@ -1171,7 +1172,7 @@ version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
dependencies = [
"base64 0.22.1",
"base64",
"rustls-pki-types",
]
@ -1236,18 +1237,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.193"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.193"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
@ -1256,11 +1257,12 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.108"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
@ -1288,16 +1290,17 @@ dependencies = [
[[package]]
name = "serde_with"
version = "3.4.0"
version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857"
dependencies = [
"base64 0.21.5",
"base64",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.1.0",
"serde",
"serde_derive",
"serde_json",
"serde_with_macros",
"time",
@ -1305,9 +1308,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "3.4.0"
version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350"
dependencies = [
"darling",
"proc-macro2",
@ -1340,6 +1343,12 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "strsim"
version = "0.10.0"
@ -1348,28 +1357,15 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strum"
version = "0.25.0"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
[[package]]
name = "strum_macros"
version = "0.25.3"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "strum_macros"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck",
"proc-macro2",
@ -1395,6 +1391,17 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "system-configuration"
version = "0.5.1"
@ -1461,12 +1468,13 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.30"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
@ -1481,28 +1489,24 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.15"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
name = "tinystr"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
dependencies = [
"tinyvec_macros",
"displaydoc",
"zerovec",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.37.0"
@ -1625,21 +1629,9 @@ checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.32"
@ -1655,68 +1647,34 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "typed-builder"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e47c0496149861b7c95198088cbf36645016b1a0734cf350c50e2a38e070f38a"
dependencies = [
"typed-builder-macro",
]
[[package]]
name = "typed-builder-macro"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982ee4197351b5c9782847ef5ec1fdcaf50503fb19d68f9771adae314e72b492"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-bidi"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
[[package]]
name = "url"
version = "2.5.0"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
name = "uuid"
version = "1.6.1"
name = "utf16_iter"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560"
dependencies = [
"getrandom",
"serde",
]
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "value-bag"
@ -1999,3 +1957,82 @@ dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "write16"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
[[package]]
name = "writeable"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
[[package]]
name = "yoke"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
dependencies = [
"serde",
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerofrom"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerovec"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -1,7 +1,7 @@
[package]
authors = ["Neshura"]
name = "aob-lemmy-bot"
version = "3.0.0-rc.1"
version = "3.3.4"
edition = "2021"
description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club"
license = "GPL-3.0-or-later"
@ -17,8 +17,6 @@ systemd-units = { enable = false }
[dependencies]
chrono = "^0.4"
lemmy_api_common = "0.19.3"
lemmy_db_schema = "0.19.3"
once_cell = "^1.19"
reqwest = { version = "^0.12", features = ["blocking", "json"] }
serde = "^1.0"
@ -31,4 +29,7 @@ confy = "^0.6"
toml = "^0.8"
systemd-journal-logger = "^2.1.1"
log = "^0.4"
async-trait = "^0.1"
notify = "6.1.1"
serde_with = "3.9.0"
strum = "0.26.3"

View file

@ -1,5 +1,5 @@
use crate::{config::{Config}};
use crate::lemmy::{Lemmy};
use crate::{config::{Config}, HTTP_CLIENT};
use crate::piefed::{Piefed};
use crate::post_history::{SeriesHistory};
use chrono::{DateTime, Duration, Utc};
use std::sync::{Arc, RwLock};
@ -7,6 +7,15 @@ use notify::{Event, EventKind, event::{AccessKind, AccessMode}, RecursiveMode, W
use tokio::time::sleep;
use systemd_journal_logger::connected_to_journal;
macro_rules! debug {
($msg:tt) => {
match connected_to_journal() {
true => log::debug!("[DEBUG] {}", $msg),
false => println!("[DEBUG] {}", $msg),
}
};
}
macro_rules! info {
($msg:tt) => {
match connected_to_journal() {
@ -70,12 +79,17 @@ impl Bot {
}
pub(crate) async fn run(&mut self) {
loop {
let mut lemmy = match Lemmy::new(&self.shared_config).await {
let mut piefed = match Piefed::new(&self.shared_config).await {
Ok(data) => data,
Err(_) => continue,
Err(_) => {
sleep(Duration::seconds(10).to_std().unwrap()).await;
continue;
},
};
lemmy.get_communities().await;
piefed.get_communities().await;
self.history = SeriesHistory::load_history();
let start: DateTime<Utc> = Utc::now();
while Utc::now() - start <= Duration::minutes(60) {
@ -83,22 +97,26 @@ impl Bot {
self.ping_status().await;
let read_copy = self.shared_config.read().expect("Read Lock Failed").clone();
for series in read_copy.series {
series.update(&mut self.history, &lemmy, &self.shared_config).await;
series.update(&mut self.history, &piefed, &self.shared_config).await;
debug!("Done Updating Series");
self.wait(1, Wait::Absolute).await;
}
debug!("Awaiting Timeout");
self.wait(30, Wait::Buffer).await;
debug!("Pinging Server");
self.ping_status().await;
debug!("Awaiting Timeout 2");
self.wait(30, Wait::Absolute).await;
}
lemmy.logout().await;
piefed.logout().await;
}
}
async fn ping_status(&self) {
let read_config = &self.shared_config.read().expect("Read Lock Failed").clone();
if let Some(status_url) = &read_config.status_post_url {
match reqwest::get(status_url).await {
match HTTP_CLIENT.get(status_url).send().await {
Ok(_) => {},
Err(e) => {
let err_msg = format!("While pinging status URL: {e}");

View file

@ -2,15 +2,23 @@ use std::path::PathBuf;
use std::sync::{Arc, RwLock};
use chrono::{Timelike, Utc};
use crate::config::PostBody::Description;
use lemmy_api_common::sensitive::Sensitive;
use lemmy_db_schema::PostFeatureType;
use crate::piefed_api::post::PostFeatureType;
use crate::piefed::{Piefed, PartInfo, PostType};
use serde_derive::{Deserialize, Serialize};
use crate::lemmy::{Lemmy, PartInfo, PostType};
use crate::post_history::{SeriesHistory};
use systemd_journal_logger::connected_to_journal;
use crate::fetchers::{FetcherTrait, Fetcher};
use crate::fetchers::jnovel::{JNovelFetcher};
macro_rules! debug {
($msg:tt) => {
match connected_to_journal() {
true => log::debug!("[DEBUG] {}", $msg),
false => println!("[DEBUG] {}", $msg),
}
};
}
macro_rules! info {
($msg:tt) => {
match connected_to_journal() {
@ -80,12 +88,12 @@ impl Config {
confy::get_configuration_file_path(env!("CARGO_PKG_NAME"), "config").expect("Application will not without confy")
}
pub(crate) fn get_username(&self) -> Sensitive<String> {
Sensitive::new(self.username.clone())
pub(crate) fn get_username(&self) -> String {
self.username.clone()
}
pub(crate) fn get_password(&self) -> Sensitive<String> {
Sensitive::new(self.password.clone())
pub(crate) fn get_password(&self) -> String {
self.password.clone()
}
}
@ -113,7 +121,7 @@ pub(crate) struct SeriesConfig {
}
impl SeriesConfig {
pub(crate) async fn update(&self, history: &mut SeriesHistory, lemmy: &Lemmy, config: &Arc<RwLock<Config>>) {
pub(crate) async fn update(&self, history: &mut SeriesHistory, piefed: &Piefed, config: &Arc<RwLock<Config>>) {
let info_msg = format!("Checking {} for Updates", self.slug);
info!(info_msg);
@ -158,7 +166,7 @@ impl SeriesConfig {
continue
}
let post_data = post_info.get_post_data(self, lemmy);
let post_data = post_info.get_post_data(self, piefed);
let info = format!(
"Posting '{}' to {}",
@ -167,12 +175,18 @@ impl SeriesConfig {
);
info!(info);
let post_id = match lemmy.post(post_data).await {
Ok(data) => data,
Err(_) => {
error!("Error posting chapter");
let post_id = match piefed.post(post_data.clone()).await {
Some(data) => data,
None => {
error!("Error posting chapter, applying fix for Issue #27");
match piefed.check_community_for_post(post_data).await {
Some(data) => data,
None => {
error!("Unable to find Post via API");
return;
}
}
}
};
let read_config = config.read().expect("Read Lock Failed").clone();
@ -188,31 +202,18 @@ impl SeriesConfig {
post_info.get_post_config(self).name.as_str()
);
info!(info);
let pinned_posts = match lemmy.get_community_pinned(lemmy.get_community_id(&post_info.get_post_config(self).name)).await {
Ok(data) => data,
Err(_) => {
let pinned_posts = piefed.get_community_pinned(piefed.get_community_id(&post_info.get_post_config(self).name)).await.unwrap_or_else(|| {
error!("Pinning of Post to community failed");
continue;
}
};
vec![]
});
if !pinned_posts.is_empty() {
let community_pinned_post = &pinned_posts[0];
match lemmy
.unpin(community_pinned_post.post.id, PostFeatureType::Community)
.await {
Ok(_) => {}
Err(_) => {
if piefed.unpin(community_pinned_post.post.id, PostFeatureType::Community).await.is_none() {
error!("Error un-pinning post");
return;
}
}
}
match lemmy.pin(post_id, PostFeatureType::Community).await {
Ok(_) => {}
Err(_) => {
if piefed.pin(post_id, PostFeatureType::Community).await.is_none() {
error!("Error pinning post");
return;
}
}
} else if read_config
.protected_communities
@ -225,48 +226,6 @@ impl SeriesConfig {
warn!(message);
}
if post_info.get_post_config(self).pin_settings.pin_new_post_local {
let info = format!("Pinning '{}' to Instance", post_info.get_info().title);
info!(info);
let pinned_posts = match lemmy.get_local_pinned().await {
Ok(data) => {data}
Err(_) => {
error!("Error fetching pinned posts");
return;
}
};
if !pinned_posts.is_empty() {
for pinned_post in pinned_posts {
if read_config
.protected_communities
.contains(&pinned_post.community.name)
{
continue;
} else {
let community_pinned_post = &pinned_post;
match lemmy
.unpin(community_pinned_post.post.id, PostFeatureType::Local)
.await {
Ok(_) => {}
Err(_) => {
error!("Error pinning post");
return;
}
}
break;
}
}
}
match lemmy.pin(post_id, PostFeatureType::Local).await {
Ok(_) => {}
Err(_) => {
error!("Error pinning post");
return;
}
};
}
let mut series_history = history.get_series(self.slug.as_str());
let mut part_history = series_history.get_part(post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str());
@ -283,6 +242,7 @@ impl SeriesConfig {
series_history.set_part(post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str(), part_history);
history
.set_series(self.slug.as_str(), series_history);
debug!("Saving History");
history.save_history();
}
}
@ -297,7 +257,6 @@ pub(crate) struct PostConfig {
#[derive(Debug, Serialize, Deserialize, Clone)]
pub(crate) struct PinConfig {
pub(crate) pin_new_post_local: bool,
pub(crate) pin_new_post_community: bool,
}

View file

@ -3,11 +3,11 @@ use chrono::{DateTime, Duration, Utc};
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::ops::Sub;
use url::Url;
use async_trait::async_trait;
use crate::fetchers::{FetcherTrait};
use crate::lemmy::{PartInfo, PostInfo, PostInfoInner, PostType};
use crate::piefed::{PartInfo, PostInfo, PostInfoInner, PostType};
use systemd_journal_logger::connected_to_journal;
use crate::lemmy::PartInfo::{NoParts, Part};
use crate::piefed::PartInfo::{NoParts, Part};
macro_rules! error {
($msg:tt) => {
@ -31,7 +31,7 @@ static PAST_DAYS_ELIGIBLE: u8 = 4;
macro_rules! api_url {
() => {
"https://labs.j-novel.club/app/v1".to_owned()
"https://labs.j-novel.club/app/v2".to_owned()
};
}
@ -94,6 +94,15 @@ pub(crate) struct JNovelFetcher {
series_has_parts: bool
}
impl Default for JNovelFetcher {
fn default() -> Self {
Self {
series_slug: "".to_owned(),
series_has_parts: false,
}
}
}
impl JNovelFetcher {
pub(crate) fn set_series(&mut self, series: String) {
self.series_slug = series;
@ -104,6 +113,7 @@ impl JNovelFetcher {
}
}
#[async_trait]
impl FetcherTrait for JNovelFetcher {
fn new() -> Self {
JNovelFetcher {
@ -190,7 +200,8 @@ impl FetcherTrait for JNovelFetcher {
);
let post_details = PostInfoInner {
title: volume.title.clone(),
url: Url::parse(&post_url).unwrap(),
url: post_url.clone(),
thumbnail: Some(volume.cover.thumbnail.clone())
};
let new_post_info = PostInfo {
@ -213,7 +224,7 @@ impl FetcherTrait for JNovelFetcher {
.or_insert(new_post_info);
}
if let Some(prepub_info) = get_latest_prepub(&volume.slug).await? {
if let Some(prepub_info) = get_latest_prepub(&volume.slug).await {
let prepub_post_info = PostInfo {
post_type: Some(PostType::Chapter),
part: Some(new_part_info),
@ -241,7 +252,7 @@ impl FetcherTrait for JNovelFetcher {
}
async fn get_latest_prepub(volume_slug: &str) -> Result<Option<PostInfoInner>, ()> {
async fn get_latest_prepub(volume_slug: &str) -> Option<PostInfoInner> {
let response = match HTTP_CLIENT
.get(api_url!() + "/volumes/" + volume_slug + "/parts?format=json")
.send()
@ -252,13 +263,13 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<PostInfoInner>, (
Err(e) => {
let err_msg = format!("While getting latest PrePub: {e}");
error!(err_msg);
return Err(());
return None;
}
},
Err(e) => {
let err_msg = format!("{e}");
error!(err_msg);
return Err(());
return None;
}
};
@ -267,7 +278,7 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<PostInfoInner>, (
Err(e) => {
let err_msg = format!("{e}");
error!(err_msg);
return Err(());
return None;
}
};
volume_prepub_parts_data.parts.reverse(); // Makes breaking out of the parts loop easier
@ -282,12 +293,15 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<PostInfoInner>, (
continue;
}
let thumbnail = prepub_part.cover.as_ref().map(|cover| cover.thumbnail.clone());
let post_url = format!("{}/read/{}", jnc_base_url!(), prepub_part.slug);
post_details = Some(PostInfoInner {
title: prepub_part.title.clone(),
url: Url::parse(&post_url).unwrap(),
url: post_url.clone(),
thumbnail
});
}
Ok(post_details)
post_details
}

View file

@ -1,11 +1,13 @@
use async_trait::async_trait;
use serde_derive::{Deserialize, Serialize};
use strum_macros::Display;
use crate::fetchers::Fetcher::Jnc;
use crate::fetchers::jnovel::JNovelFetcher;
use crate::lemmy::{PostInfo};
use crate::piefed::{PostInfo};
pub mod jnovel;
#[async_trait]
pub(crate) trait FetcherTrait {
fn new() -> Self where Self: Sized;
async fn check_feed(&self) -> Result<Vec<PostInfo>, ()>;
@ -27,5 +29,5 @@ impl Fetcher {
#[derive(Deserialize, Serialize, Debug, Clone, Display)]
pub(crate) enum Fetcher {
#[serde(rename = "jnc")]
Jnc(JNovelFetcher)
Jnc(#[serde(skip)] JNovelFetcher)
}

View file

@ -7,9 +7,10 @@ use crate::bot::Bot;
mod bot;
mod config;
mod lemmy;
mod piefed;
mod post_history;
mod fetchers;
mod piefed_api;
pub static HTTP_CLIENT: Lazy<Client> = Lazy::new(|| {
Client::builder()
@ -25,7 +26,17 @@ async fn main() {
.expect("Systemd-Logger crate error")
.install()
.expect("Systemd-Logger crate error");
log::set_max_level(LevelFilter::Info);
match std::env::var("LOG_LEVEL") {
Ok(level) => {
match level.as_str() {
"debug" => log::set_max_level(LevelFilter::Debug),
"info" => log::set_max_level(LevelFilter::Info),
_ => log::set_max_level(LevelFilter::Info),
}
}
_ => log::set_max_level(LevelFilter::Info),
}
let mut bot = Bot::new();
bot.run().await;
}

View file

@ -1,20 +1,34 @@
use std::cmp::Ordering;
use crate::config::{Config, PostBody, PostConfig, SeriesConfig};
use crate::{HTTP_CLIENT};
use lemmy_api_common::community::{ListCommunities, ListCommunitiesResponse};
use lemmy_api_common::lemmy_db_views::structs::PostView;
use lemmy_api_common::person::{Login, LoginResponse};
use lemmy_api_common::post::{CreatePost, FeaturePost, GetPosts, GetPostsResponse};
use lemmy_api_common::sensitive::Sensitive;
use lemmy_db_schema::newtypes::{CommunityId, LanguageId, PostId};
use lemmy_db_schema::{ListingType, PostFeatureType};
use crate::piefed_api::user::{Login, LoginResponse};
use crate::piefed_api::post::{PostView, CreatePost, FeaturePost, GetPosts, GetPostsResponse, PostFeatureType, ListingType, SortType, PostSortType};
use crate::piefed_api::types::{CommunityId, LanguageId, PostId};
use crate::piefed_api::community::{ListCommunitiesParams, ListCommunitiesResponse};
use reqwest::StatusCode;
use std::collections::HashMap;
use std::sync::{RwLock};
use serde::{Deserialize, Serialize};
use url::Url;
use systemd_journal_logger::connected_to_journal;
macro_rules! debug {
($msg:tt) => {
match connected_to_journal() {
true => log::debug!("[DEBUG] {}", $msg),
false => println!("[DEBUG] {}", $msg),
}
};
}
macro_rules! info {
($msg:tt) => {
match connected_to_journal() {
true => log::info!("[INFO] {}", $msg),
false => println!("[INFO] {}", $msg),
}
};
}
macro_rules! error {
($msg:tt) => {
match connected_to_journal() {
@ -24,8 +38,8 @@ macro_rules! error {
};
}
pub(crate) struct Lemmy {
jwt_token: Sensitive<String>,
pub(crate) struct Piefed {
jwt_token: String,
instance: String,
communities: HashMap<String, CommunityId>,
}
@ -34,7 +48,8 @@ pub(crate) struct Lemmy {
#[derive(Debug, Clone)]
pub(crate) struct PostInfoInner {
pub(crate) title: String,
pub(crate) url: Url,
pub(crate) url: String,
pub(crate) thumbnail: Option<String>
}
#[derive(Debug, Copy, Clone)]
@ -137,7 +152,7 @@ impl PostInfo {
}
}
pub(crate) fn get_post_data(&self, series: &SeriesConfig, lemmy: &Lemmy) -> CreatePost {
pub(crate) fn get_post_data(&self, series: &SeriesConfig, lemmy: &Piefed) -> CreatePost {
let post_config = self.get_post_config(series);
let post_body = match &post_config.post_body {
@ -149,13 +164,13 @@ impl PostInfo {
let community_id: CommunityId = lemmy.get_community_id(&post_config.name);
CreatePost {
name: self.get_info().title.clone(),
title: self.get_info().title.clone(),
community_id,
url: Some(self.get_info().url),
//custom_thumbnail: self.get_info().thumbnail,
body: post_body,
honeypot: None,
nsfw: None,
language_id: Some(LanguageId(37)), // TODO get this id once every few hours per API request, the ordering of IDs suggests that the EN Id might change in the future
nsfw: false,
language_id: LanguageId(37), // TODO get this id once every few hours per API request, the ordering of IDs suggests that the EN Id might change in the future
}
}
}
@ -194,20 +209,19 @@ impl PartialOrd for PostInfo {
}
}
impl Lemmy {
impl Piefed {
pub(crate) fn get_community_id(&self, name: &str) -> CommunityId {
*self.communities.get(name).expect("Given community is invalid")
}
pub(crate) async fn new(config: &RwLock<Config>) -> Result<Self, ()> {
let read_config = config.read().expect("Read Lock Failed").clone();
let login_params = Login {
username_or_email: read_config.get_username(),
username: read_config.get_username(),
password: read_config.get_password(),
totp_2fa_token: None,
};
let response = match HTTP_CLIENT
.post(read_config.instance.to_owned() + "/api/v3/user/login")
.post(read_config.instance.to_owned() + "/api/alpha/user/login")
.json(&login_params)
.send()
.await
@ -223,11 +237,11 @@ impl Lemmy {
match response.status() {
StatusCode::OK => {
let data: LoginResponse = response
.json()
.json::<LoginResponse>()
.await
.expect("Successful Login Request should return JSON");
match data.jwt {
Some(token) => Ok(Lemmy {
Some(token) => Ok(Piefed {
jwt_token: token.clone(),
instance: read_config.instance.to_owned(),
communities: HashMap::new(),
@ -248,25 +262,37 @@ impl Lemmy {
}
pub(crate) async fn logout(&self) {
let _ = self.post_data_json("/api/v3/user/logout", &"").await;
let _ = self.post_data_json("/api/alpha/user/logout", &"").await;
}
pub(crate) async fn post(&self, post: CreatePost) -> Result<PostId, ()> {
let response: String = self.post_data_json("/api/v3/post", &post).await?;
let json_data: PostView = self.parse_json_map(&response).await?;
pub(crate) async fn post(&self, post: CreatePost) -> Option<PostId> {
let response: String = match self.post_data_json("/api/alpha/post", &post).await {
Some(data) => data,
None => return None,
};
let json_data: PostView = match self.parse_json_map(&response).await {
Some(data) => data,
None => return None,
};
Ok(json_data.post.id)
Some(json_data.post.id)
}
async fn feature(&self, params: FeaturePost) -> Result<PostView, ()> {
let response: String = self.post_data_json("/api/v3/post/feature", &params).await?;
let json_data: PostView = self.parse_json_map(&response).await?;
async fn feature(&self, params: FeaturePost) -> Option<PostView> {
let response: String = match self.post_data_json("/api/alpha/post/feature", &params).await {
Some(data) => data,
None => return None,
};
let json_data: PostView = match self.parse_json_map(&response).await {
Some(data) => data,
None => return None,
};
Ok(json_data)
Some(json_data)
}
pub(crate) async fn unpin(&self, post_id: PostId, location: PostFeatureType) -> Result<PostView, ()> {
pub(crate) async fn unpin(&self, post_id: PostId, location: PostFeatureType) -> Option<PostView> {
let pin_params = FeaturePost {
post_id,
featured: false,
@ -275,7 +301,7 @@ impl Lemmy {
self.feature(pin_params).await
}
pub(crate) async fn pin(&self, post_id: PostId, location: PostFeatureType) -> Result<PostView, ()> {
pub(crate) async fn pin(&self, post_id: PostId, location: PostFeatureType) -> Option<PostView> {
let pin_params = FeaturePost {
post_id,
featured: true,
@ -284,60 +310,46 @@ impl Lemmy {
self.feature(pin_params).await
}
pub(crate) async fn get_community_pinned(&self, community: CommunityId) -> Result<Vec<PostView>, ()> {
pub(crate) async fn get_community_pinned(&self, community: CommunityId) -> Option<Vec<PostView>> {
let list_params = GetPosts {
community_id: Some(community),
type_: Some(ListingType::Local),
..Default::default()
};
let response: String = self.get_data_query("/api/v3/post/list", &list_params).await?;
let json_data: GetPostsResponse = self.parse_json(&response).await?;
Ok(json_data
.posts
.iter()
.filter(|post| post.post.featured_community)
.cloned()
.collect())
}
pub(crate) async fn get_local_pinned(&self) -> Result<Vec<PostView>, ()> {
let list_params = GetPosts {
type_: Some(ListingType::Local),
..Default::default()
let response: String = match self.get_data_query("/api/alpha/post/list", &list_params).await {
Some(data) => data,
None => return None,
};
let json_data: GetPostsResponse = match self.parse_json(&response).await {
Some(data) => data,
None => return None,
};
let response: String = self.get_data_query("/api/v3/post/list", &list_params).await?;
let json_data: GetPostsResponse = self.parse_json(&response).await?;
Ok(json_data
Some(json_data
.posts
.iter()
.filter(|post| post.post.featured_local)
.filter(|post| post.post.sticky)
.cloned()
.collect())
}
pub(crate) async fn get_communities(&mut self) {
let list_params = ListCommunities {
let list_params = ListCommunitiesParams {
type_: Some(ListingType::Local),
..Default::default()
sort: Some(SortType::New),
show_nsfw: Some(false),
page: Some(0),
limit: Some(100)
};
let response: String = match self.get_data_query("/api/v3/community/list", &list_params).await {
Ok(data) => data,
Err(_) => {
error!("Unable to extract data from request");
return;
}
let response: String = match self.get_data_query("/api/alpha/community/list", &list_params).await {
Some(data) => data,
None => return,
};
let json_data: ListCommunitiesResponse = match self.parse_json::<ListCommunitiesResponse>(&response).await {
Ok(data) => data,
Err(_) => {
error!("Unable to parse data from json");
return;
},
Some(data) => data,
None => return,
};
let mut communities: HashMap<String, CommunityId> = HashMap::new();
@ -349,62 +361,109 @@ impl Lemmy {
self.communities = communities;
}
async fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> {
pub(crate) async fn check_community_for_post(&self, post: CreatePost) -> Option<PostId> {
let get_params: GetPosts = GetPosts {
type_: None,
sort: Some(PostSortType::New),
page: None,
limit: None,
community_id: Some(post.community_id),
person_id: None,
community_name: None,
liked_only: None,
};
let response: String = match self.get_data_query("/api/alpha/post/list", &get_params).await {
Some(data) => data,
None => {
error!("Unable to query post list");
return None
},
};
let json_data: GetPostsResponse = match self.parse_json(&response).await {
Some(data) => data,
None => {
error!("Unable to parse post data");
return None
},
};
for api_post in json_data.posts {
if api_post.post.title == post.title {
return Some(api_post.post.id);
}
}
let msg = format!("Unable to find post {}", post.title);
info!(msg);
None
}
async fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Option<String> {
let res = HTTP_CLIENT
.post(format!("{}{route}", &self.instance))
.bearer_auth(&self.jwt_token.to_string())
.bearer_auth(self.jwt_token.to_string())
.json(&json)
.send()
.await;
self.extract_data(res).await
}
async fn get_data_query<T: Serialize>(&self, route: &str, param: &T ) -> Result<String,()> {
async fn get_data_query<T: Serialize>(&self, route: &str, param: &T ) -> Option<String> {
let res = HTTP_CLIENT
.get(format!("{}{route}", &self.instance))
.bearer_auth(&self.jwt_token.to_string())
.bearer_auth(self.jwt_token.to_string())
.query(&param)
.send()
.await;
self.extract_data(res).await
}
async fn extract_data(&self, response: Result<reqwest::Response, reqwest::Error>) -> Result<String,()> {
async fn extract_data(&self, response: Result<reqwest::Response, reqwest::Error>) -> Option<String> {
match response {
Ok(data) => match data.text().await {
Ok(data) => Ok(data),
Ok(data) => {
if data.status().is_success() {
match data.text().await {
Ok(data) => Some(data),
Err(e) => {
let err_msg = format!("{e}");
error!(err_msg);
Err(())
None
}
}
}
else {
let err_msg = format!("HTTP Request failed: {}", data.text().await.unwrap());
error!(err_msg);
None
}
},
Err(e) => {
let err_msg = format!("{e}");
error!(err_msg);
Err(())
None
}
}
}
async fn parse_json<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Result<T,()> {
async fn parse_json<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Option<T> {
match serde_json::from_str::<T>(response) {
Ok(data) => Ok(data),
Ok(data) => Some(data),
Err(e) => {
let err_msg = format!("{e} while parsing JSON");
let err_msg = format!("while parsing JSON: {e} ");
error!(err_msg);
Err(())
None
}
}
}
async fn parse_json_map<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Result<T,()> {
async fn parse_json_map<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Option<T> {
debug!(response);
match serde_json::from_str::<HashMap<&str, T>>(response) {
Ok(mut data) => Ok(data.remove("post_view").expect("Element should be present")),
Ok(mut data) => Some(data.remove("post_view").expect("Element should be present")),
Err(e) => {
let err_msg = format!("{e} while parsing JSON HashMap");
let err_msg = format!("while parsing JSON HashMap: {e}");
error!(err_msg);
Err(())
None
}
}
}

View file

@ -0,0 +1,63 @@
use serde_derive::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use crate::piefed_api::post::{ListingType, SortType};
use crate::piefed_api::types::{CommunityId, PostId, SubscribedType};
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct CommunityCounts {
pub id: CommunityId,
pub post_count: i32,
pub post_reply_count: i32,
pub subscriptions_count: i32,
pub published: String,
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct Community {
pub actor_id: String,
pub ap_domain: String,
pub banned: bool,
pub banner: Option<String>,
pub deleted: bool,
pub description: Option<String>,
pub hidden: bool,
pub icon: Option<String>,
pub id: CommunityId,
pub instance_id: u32,
pub local: bool,
pub name: String,
pub nsfw: bool,
pub published: String,
pub removed: bool,
pub restricted_to_mods: bool,
pub title: String,
pub updated: String,
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct ListCommunitiesParams {
pub type_: Option<ListingType>,
pub sort: Option<SortType>,
pub show_nsfw: Option<bool>,
pub page: Option<i32>,
pub limit: Option<i32>,
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct ListCommunitiesResponse {
pub communities: Vec<CommunityView>,
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct CommunityView {
pub community: Community,
pub subscribed: SubscribedType,
pub blocked: bool,
pub counts: CommunityCounts,
pub activity_alert: bool
}

4
src/piefed_api/mod.rs Normal file
View file

@ -0,0 +1,4 @@
pub mod user;
pub mod post;
pub mod types;
pub mod community;

161
src/piefed_api/post.rs Normal file
View file

@ -0,0 +1,161 @@
use serde_derive::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use strum_macros::{Display, EnumString};
use crate::piefed_api::community::Community;
use crate::piefed_api::types::{CommunityId, LanguageId, PaginationCursor, PersonId, PostId, SubscribedType};
use crate::piefed_api::user::Person;
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash,
)]
pub enum PostFeatureType {
#[default]
Local,
Community,
}
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
)]
pub enum ListingType {
All,
#[default]
Local,
Subscribed,
ModeratorView,
}
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
)]
pub enum SortType {
#[default]
Active,
Hot,
New,
Old,
TopDay,
TopWeek,
TopMonth,
TopYear,
TopAll,
MostComments,
NewComments,
TopHour,
TopSixHour,
TopTwelveHour,
TopThreeMonths,
TopSixMonths,
TopNineMonths,
Controversial,
Scaled,
}
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
)]
pub enum PostSortType {
#[default]
Active,
Hot,
New,
Old,
Top,
MostComments,
NewComments,
Controversial,
Scaled,
}
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct GetPosts {
pub type_: Option<ListingType>,
pub sort: Option<PostSortType>,
pub page: Option<PaginationCursor>,
pub limit: Option<i64>,
pub community_id: Option<CommunityId>,
pub person_id: Option<PersonId>,
pub community_name: Option<String>,
pub liked_only: Option<bool>,
}
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GetPostsResponse {
pub posts: Vec<PostView>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct FeaturePost {
pub post_id: PostId,
pub featured: bool,
pub feature_type: PostFeatureType,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
pub struct CreatePost {
pub title: String,
pub community_id: CommunityId,
pub url: Option<String>,
pub body: Option<String>,
pub nsfw: bool,
pub language_id: LanguageId,
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct PostView {
pub post: Post,
pub creator: Person,
pub community: Community,
pub creator_banned_from_community: bool,
pub banned_from_community: bool,
pub creator_is_moderator: bool,
pub creator_is_admin: bool,
pub counts: PostCounts,
pub subscribed: SubscribedType,
pub saved: bool,
pub activity_alert: bool,
pub read: bool,
pub hidden: bool,
pub my_vote: i32,
pub unread_comments: i32,
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct PostCounts {
pub post_id: PostId,
pub comments: i32,
pub score: i32,
pub upvotes: i32,
pub downvotes: i32,
pub published: String,
pub newest_comment_time: String,
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct Post {
pub id: PostId,
pub title: String,
pub url: Option<String>,
pub body: Option<String>,
pub user_id: PersonId,
pub community_id: CommunityId,
pub removed: bool,
pub locked: bool,
pub published: String,
pub updated: Option<String>,
pub deleted: bool,
pub nsfw: bool,
pub thumbnail_url: Option<String>,
pub ap_id: String,
pub local: bool,
pub language_id: Option<LanguageId>,
pub sticky: bool,
pub alt_text: Option<String>,
}

19
src/piefed_api/types.rs Normal file
View file

@ -0,0 +1,19 @@
use serde_derive::{Deserialize, Serialize};
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct CommunityId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct PersonId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
/// The post id.
pub struct PostId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct LanguageId(pub i32);
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct PaginationCursor(pub String);
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub enum SubscribedType {
Subscribed,
NotSubscribed,
}

33
src/piefed_api/user.rs Normal file
View file

@ -0,0 +1,33 @@
use serde_derive::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use crate::piefed_api::types::PersonId;
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
pub struct Login {
pub username: String,
pub password: String,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct LoginResponse {
pub jwt: Option<String>,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct Person {
pub actor_id: String,
pub avatar: Option<String>,
pub banned: bool,
pub banner: Option<String>,
pub bot: bool,
pub deleted: bool,
pub id: PersonId,
pub instance_id: u32,
pub local: bool,
pub published: String,
pub title: String,
pub user_name: String,
}