* Add RSS feeds * feat(rss): feature-ify rss * feat(rss): config-ify rss * fix(rss): update info page * feat(rss): conditionally add RSS feeds to user and sub pages * feat(rss): implement URLs for RSS
This commit is contained in:
parent
9bdb5c8966
commit
374238abc3
234
Cargo.lock
generated
234
Cargo.lock
generated
@ -98,7 +98,7 @@ dependencies = [
|
|||||||
"mime_guess",
|
"mime_guess",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -124,7 +124,20 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atom_syndication"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2f34613907f31c9dbef0240156db3c9263f34842b6e1a8999d2304ea62c8a30"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"derive_builder 0.20.0",
|
||||||
|
"diligent-date-parser",
|
||||||
|
"never",
|
||||||
|
"quick-xml 0.31.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -236,10 +249,10 @@ version = "0.21.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "771aa57f3b17da6c8bcacb187bb9ec9bc81c8160e72342e67c329e0e1651a669"
|
checksum = "771aa57f3b17da6c8bcacb187bb9ec9bc81c8160e72342e67c329e0e1651a669"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling 0.20.9",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -260,6 +273,15 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.7"
|
version = "4.5.7"
|
||||||
@ -348,14 +370,38 @@ dependencies = [
|
|||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core 0.14.4",
|
||||||
|
"darling_macro 0.14.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.20.9"
|
version = "0.20.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1"
|
checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core 0.20.9",
|
||||||
"darling_macro",
|
"darling_macro 0.20.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim 0.10.0",
|
||||||
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -368,8 +414,19 @@ dependencies = [
|
|||||||
"ident_case",
|
"ident_case",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim",
|
"strsim 0.11.1",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core 0.14.4",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -378,9 +435,9 @@ version = "0.20.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178"
|
checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core 0.20.9",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -398,6 +455,68 @@ dependencies = [
|
|||||||
"powerfmt",
|
"powerfmt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_builder"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
|
||||||
|
dependencies = [
|
||||||
|
"derive_builder_macro 0.12.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_builder"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7"
|
||||||
|
dependencies = [
|
||||||
|
"derive_builder_macro 0.20.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_builder_core"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
|
||||||
|
dependencies = [
|
||||||
|
"darling 0.14.4",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_builder_core"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d"
|
||||||
|
dependencies = [
|
||||||
|
"darling 0.20.9",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.68",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_builder_macro"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
|
||||||
|
dependencies = [
|
||||||
|
"derive_builder_core 0.12.0",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_builder_macro"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
|
||||||
|
dependencies = [
|
||||||
|
"derive_builder_core 0.20.0",
|
||||||
|
"syn 2.0.68",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
@ -408,12 +527,30 @@ dependencies = [
|
|||||||
"crypto-common",
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diligent-date-parser"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6cf7fe294274a222363f84bcb63cdea762979a0443b4cf1f4f8fd17c86b1182"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenvy"
|
name = "dotenvy"
|
||||||
version = "0.15.7"
|
version = "0.15.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding_rs"
|
||||||
|
version = "0.8.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@ -862,6 +999,12 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "never"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
@ -878,6 +1021,15 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@ -1002,6 +1154,26 @@ version = "1.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-xml"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_rs",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-xml"
|
||||||
|
version = "0.31.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_rs",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.36"
|
version = "1.0.36"
|
||||||
@ -1061,6 +1233,7 @@ dependencies = [
|
|||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"regex",
|
"regex",
|
||||||
"route-recognizer",
|
"route-recognizer",
|
||||||
|
"rss",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"sealed_test",
|
"sealed_test",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1138,6 +1311,18 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746"
|
checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rss"
|
||||||
|
version = "2.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7b2c77eb4450d7d5f98df52c381cd6c4e19b75dad9209a9530b85a44510219a"
|
||||||
|
dependencies = [
|
||||||
|
"atom_syndication",
|
||||||
|
"derive_builder 0.12.0",
|
||||||
|
"never",
|
||||||
|
"quick-xml 0.30.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-embed"
|
name = "rust-embed"
|
||||||
version = "8.4.0"
|
version = "8.4.0"
|
||||||
@ -1158,7 +1343,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rust-embed-utils",
|
"rust-embed-utils",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1307,7 +1492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "77253fb2d4451418d07025826028bcb96ee42d3e58859689a70ce62908009db6"
|
checksum = "77253fb2d4451418d07025826028bcb96ee42d3e58859689a70ce62908009db6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1350,7 +1535,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1437,6 +1622,12 @@ version = "0.9.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@ -1449,6 +1640,17 @@ version = "2.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.68"
|
version = "2.0.68"
|
||||||
@ -1498,7 +1700,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1576,7 +1778,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1950,7 +2152,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.68",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -42,8 +42,10 @@ fastrand = "2.0.1"
|
|||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
pretty_env_logger = "0.5.0"
|
pretty_env_logger = "0.5.0"
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
|
rss = "2.0.7"
|
||||||
arc-swap = "1.7.1"
|
arc-swap = "1.7.1"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lipsum = "0.9.0"
|
lipsum = "0.9.0"
|
||||||
sealed_test = "1.0.0"
|
sealed_test = "1.0.0"
|
||||||
|
@ -381,7 +381,8 @@ Assign a default value for each instance-specific setting by passing environment
|
|||||||
| `ROBOTS_DISABLE_INDEXING` | `["on", "off"]` | `off` | Disables indexing of the instance by search engines. |
|
| `ROBOTS_DISABLE_INDEXING` | `["on", "off"]` | `off` | Disables indexing of the instance by search engines. |
|
||||||
| `PUSHSHIFT_FRONTEND` | String | `undelete.pullpush.io` | Allows the server to set the Pushshift frontend to be used with "removed" links. |
|
| `PUSHSHIFT_FRONTEND` | String | `undelete.pullpush.io` | Allows the server to set the Pushshift frontend to be used with "removed" links. |
|
||||||
| `PORT` | Integer 0-65535 | `8080` | The **internal** port Redlib listens on. |
|
| `PORT` | Integer 0-65535 | `8080` | The **internal** port Redlib listens on. |
|
||||||
|
| `ENABLE_RSS` | `["on", "off"]` | `off` | Enables RSS feed generation. |
|
||||||
|
| `FULL_URL` | String | (empty) | Allows for proper URLs (for now, only needed by RSS)
|
||||||
## Default user settings
|
## Default user settings
|
||||||
|
|
||||||
Assign a default value for each user-modifiable setting by passing environment variables to Redlib in the format `REDLIB_DEFAULT_{Y}`. Replace `{Y}` with the setting name (see list below) in capital letters.
|
Assign a default value for each user-modifiable setting by passing environment variables to Redlib in the format `REDLIB_DEFAULT_{Y}`. Replace `{Y}` with the setting name (see list below) in capital letters.
|
||||||
|
10
app.json
10
app.json
@ -56,8 +56,8 @@
|
|||||||
"REDLIB_BANNER": {
|
"REDLIB_BANNER": {
|
||||||
"required": false
|
"required": false
|
||||||
},
|
},
|
||||||
"REDLIB_ROBOTS_DISABLE_INDEXING": {
|
"REDLIB_ROBOTS_DISABLE_INDEXING": {
|
||||||
"required": false
|
"required": false
|
||||||
},
|
},
|
||||||
"REDLIB_DEFAULT_SUBSCRIPTIONS": {
|
"REDLIB_DEFAULT_SUBSCRIPTIONS": {
|
||||||
"required": false
|
"required": false
|
||||||
@ -70,6 +70,12 @@
|
|||||||
},
|
},
|
||||||
"REDLIB_PUSHSHIFT_FRONTEND": {
|
"REDLIB_PUSHSHIFT_FRONTEND": {
|
||||||
"required": false
|
"required": false
|
||||||
|
},
|
||||||
|
"REDLIB_ENABLE_RSS": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"REDLIB_FULL_URL": {
|
||||||
|
"required": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,12 @@ pub struct Config {
|
|||||||
#[serde(rename = "REDLIB_PUSHSHIFT_FRONTEND")]
|
#[serde(rename = "REDLIB_PUSHSHIFT_FRONTEND")]
|
||||||
#[serde(alias = "LIBREDDIT_PUSHSHIFT_FRONTEND")]
|
#[serde(alias = "LIBREDDIT_PUSHSHIFT_FRONTEND")]
|
||||||
pub(crate) pushshift: Option<String>,
|
pub(crate) pushshift: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "REDLIB_ENABLE_RSS")]
|
||||||
|
pub(crate) enable_rss: Option<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "REDLIB_FULL_URL")]
|
||||||
|
pub(crate) full_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@ -148,6 +154,8 @@ impl Config {
|
|||||||
banner: parse("REDLIB_BANNER"),
|
banner: parse("REDLIB_BANNER"),
|
||||||
robots_disable_indexing: parse("REDLIB_ROBOTS_DISABLE_INDEXING"),
|
robots_disable_indexing: parse("REDLIB_ROBOTS_DISABLE_INDEXING"),
|
||||||
pushshift: parse("REDLIB_PUSHSHIFT_FRONTEND"),
|
pushshift: parse("REDLIB_PUSHSHIFT_FRONTEND"),
|
||||||
|
enable_rss: parse("REDLIB_ENABLE_RSS"),
|
||||||
|
full_url: parse("REDLIB_FULL_URL"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,6 +183,8 @@ fn get_setting_from_config(name: &str, config: &Config) -> Option<String> {
|
|||||||
"REDLIB_BANNER" => config.banner.clone(),
|
"REDLIB_BANNER" => config.banner.clone(),
|
||||||
"REDLIB_ROBOTS_DISABLE_INDEXING" => config.robots_disable_indexing.clone(),
|
"REDLIB_ROBOTS_DISABLE_INDEXING" => config.robots_disable_indexing.clone(),
|
||||||
"REDLIB_PUSHSHIFT_FRONTEND" => config.pushshift.clone(),
|
"REDLIB_PUSHSHIFT_FRONTEND" => config.pushshift.clone(),
|
||||||
|
"REDLIB_ENABLE_RSS" => config.enable_rss.clone(),
|
||||||
|
"REDLIB_FULL_URL" => config.full_url.clone(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,8 @@ impl InstanceInfo {
|
|||||||
["Compile mode", &self.compile_mode],
|
["Compile mode", &self.compile_mode],
|
||||||
["SFW only", &convert(&self.config.sfw_only)],
|
["SFW only", &convert(&self.config.sfw_only)],
|
||||||
["Pushshift frontend", &convert(&self.config.pushshift)],
|
["Pushshift frontend", &convert(&self.config.pushshift)],
|
||||||
|
["RSS enabled", &convert(&self.config.enable_rss)],
|
||||||
|
["Full URL", &convert(&self.config.full_url)],
|
||||||
//TODO: fallback to crate::config::DEFAULT_PUSHSHIFT_FRONTEND
|
//TODO: fallback to crate::config::DEFAULT_PUSHSHIFT_FRONTEND
|
||||||
])
|
])
|
||||||
.with_header_row(["Settings"]),
|
.with_header_row(["Settings"]),
|
||||||
@ -165,6 +167,8 @@ impl InstanceInfo {
|
|||||||
Compile mode: {}\n
|
Compile mode: {}\n
|
||||||
SFW only: {:?}\n
|
SFW only: {:?}\n
|
||||||
Pushshift frontend: {:?}\n
|
Pushshift frontend: {:?}\n
|
||||||
|
RSS enabled: {:?}\n
|
||||||
|
Full URL: {:?}\n
|
||||||
Config:\n
|
Config:\n
|
||||||
Banner: {:?}\n
|
Banner: {:?}\n
|
||||||
Hide awards: {:?}\n
|
Hide awards: {:?}\n
|
||||||
@ -189,6 +193,8 @@ impl InstanceInfo {
|
|||||||
self.deploy_unix_ts,
|
self.deploy_unix_ts,
|
||||||
self.compile_mode,
|
self.compile_mode,
|
||||||
self.config.sfw_only,
|
self.config.sfw_only,
|
||||||
|
self.config.enable_rss,
|
||||||
|
self.config.full_url,
|
||||||
self.config.pushshift,
|
self.config.pushshift,
|
||||||
self.config.banner,
|
self.config.banner,
|
||||||
self.config.default_hide_awards,
|
self.config.default_hide_awards,
|
||||||
|
@ -254,6 +254,7 @@ async fn main() {
|
|||||||
app.at("/u/:name/comments/:id/:title/:comment_id").get(|r| post::item(r).boxed());
|
app.at("/u/:name/comments/:id/:title/:comment_id").get(|r| post::item(r).boxed());
|
||||||
|
|
||||||
app.at("/user/[deleted]").get(|req| error(req, "User has deleted their account").boxed());
|
app.at("/user/[deleted]").get(|req| error(req, "User has deleted their account").boxed());
|
||||||
|
app.at("/user/:name.rss").get(|r| user::rss(r).boxed());
|
||||||
app.at("/user/:name").get(|r| user::profile(r).boxed());
|
app.at("/user/:name").get(|r| user::profile(r).boxed());
|
||||||
app.at("/user/:name/:listing").get(|r| user::profile(r).boxed());
|
app.at("/user/:name/:listing").get(|r| user::profile(r).boxed());
|
||||||
app.at("/user/:name/comments/:id").get(|r| post::item(r).boxed());
|
app.at("/user/:name/comments/:id").get(|r| post::item(r).boxed());
|
||||||
@ -265,6 +266,9 @@ async fn main() {
|
|||||||
app.at("/settings/restore").get(|r| settings::restore(r).boxed());
|
app.at("/settings/restore").get(|r| settings::restore(r).boxed());
|
||||||
app.at("/settings/update").get(|r| settings::update(r).boxed());
|
app.at("/settings/update").get(|r| settings::update(r).boxed());
|
||||||
|
|
||||||
|
// RSS Subscriptions
|
||||||
|
app.at("/r/:sub.rss").get(|r| subreddit::rss(r).boxed());
|
||||||
|
|
||||||
// Subreddit services
|
// Subreddit services
|
||||||
app
|
app
|
||||||
.at("/r/:sub")
|
.at("/r/:sub")
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::{config, utils};
|
||||||
// CRATES
|
// CRATES
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
catch_random, error, filter_posts, format_num, format_url, get_filters, nsfw_landing, param, redirect, rewrite_urls, setting, template, val, Post, Preferences, Subreddit,
|
catch_random, error, filter_posts, format_num, format_url, get_filters, nsfw_landing, param, redirect, rewrite_urls, setting, template, val, Post, Preferences, Subreddit,
|
||||||
@ -459,6 +460,56 @@ async fn subreddit(sub: &str, quarantined: bool) -> Result<Subreddit, String> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn rss(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||||
|
if config::get_setting("REDLIB_ENABLE_RSS").is_none() {
|
||||||
|
return Ok(error(req, "RSS is disabled on this instance.").await.unwrap_or_default());
|
||||||
|
}
|
||||||
|
|
||||||
|
use hyper::header::CONTENT_TYPE;
|
||||||
|
use rss::{ChannelBuilder, Item};
|
||||||
|
|
||||||
|
// Get subreddit
|
||||||
|
let sub = req.param("sub").unwrap_or_default();
|
||||||
|
let post_sort = req.cookie("post_sort").map_or_else(|| "hot".to_string(), |c| c.value().to_string());
|
||||||
|
let sort = req.param("sort").unwrap_or_else(|| req.param("id").unwrap_or(post_sort));
|
||||||
|
|
||||||
|
// Get path
|
||||||
|
let path = format!("/r/{sub}/{sort}.json?{}", req.uri().query().unwrap_or_default());
|
||||||
|
|
||||||
|
// Get subreddit data
|
||||||
|
let subreddit = subreddit(&sub, false).await?;
|
||||||
|
|
||||||
|
// Get posts
|
||||||
|
let (posts, _) = Post::fetch(&path, false).await?;
|
||||||
|
|
||||||
|
// Build the RSS feed
|
||||||
|
let channel = ChannelBuilder::default()
|
||||||
|
.title(&subreddit.title)
|
||||||
|
.description(&subreddit.description)
|
||||||
|
.items(
|
||||||
|
posts
|
||||||
|
.into_iter()
|
||||||
|
.map(|post| Item {
|
||||||
|
title: Some(post.title.to_string()),
|
||||||
|
link: Some(utils::get_post_url(&post)),
|
||||||
|
author: Some(post.author.name),
|
||||||
|
content: Some(rewrite_urls(&post.body)),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Serialize the feed to RSS
|
||||||
|
let body = channel.to_string().into_bytes();
|
||||||
|
|
||||||
|
// Create the HTTP response
|
||||||
|
let mut res = Response::new(Body::from(body));
|
||||||
|
res.headers_mut().insert(CONTENT_TYPE, hyper::header::HeaderValue::from_static("application/rss+xml"));
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn test_fetching_subreddit() {
|
async fn test_fetching_subreddit() {
|
||||||
let subreddit = subreddit("rust", false).await;
|
let subreddit = subreddit("rust", false).await;
|
||||||
|
51
src/user.rs
51
src/user.rs
@ -2,6 +2,7 @@
|
|||||||
use crate::client::json;
|
use crate::client::json;
|
||||||
use crate::server::RequestExt;
|
use crate::server::RequestExt;
|
||||||
use crate::utils::{error, filter_posts, format_url, get_filters, nsfw_landing, param, setting, template, Post, Preferences, User};
|
use crate::utils::{error, filter_posts, format_url, get_filters, nsfw_landing, param, setting, template, Post, Preferences, User};
|
||||||
|
use crate::{config, utils};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use hyper::{Body, Request, Response};
|
use hyper::{Body, Request, Response};
|
||||||
use time::{macros::format_description, OffsetDateTime};
|
use time::{macros::format_description, OffsetDateTime};
|
||||||
@ -129,6 +130,56 @@ async fn user(name: &str) -> Result<User, String> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn rss(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||||
|
if config::get_setting("REDLIB_ENABLE_RSS").is_none() {
|
||||||
|
return Ok(error(req, "RSS is disabled on this instance.").await.unwrap_or_default());
|
||||||
|
}
|
||||||
|
use crate::utils::rewrite_urls;
|
||||||
|
use hyper::header::CONTENT_TYPE;
|
||||||
|
use rss::{ChannelBuilder, Item};
|
||||||
|
|
||||||
|
// Get user
|
||||||
|
let user_str = req.param("name").unwrap_or_default();
|
||||||
|
|
||||||
|
let listing = req.param("listing").unwrap_or_else(|| "overview".to_string());
|
||||||
|
|
||||||
|
// Get path
|
||||||
|
let path = format!("/user/{user_str}/{listing}.json?{}&raw_json=1", req.uri().query().unwrap_or_default(),);
|
||||||
|
|
||||||
|
// Get user
|
||||||
|
let user_obj = user(&user_str).await.unwrap_or_default();
|
||||||
|
|
||||||
|
// Get posts
|
||||||
|
let (posts, _) = Post::fetch(&path, false).await?;
|
||||||
|
|
||||||
|
// Build the RSS feed
|
||||||
|
let channel = ChannelBuilder::default()
|
||||||
|
.title(user_str)
|
||||||
|
.description(user_obj.description)
|
||||||
|
.items(
|
||||||
|
posts
|
||||||
|
.into_iter()
|
||||||
|
.map(|post| Item {
|
||||||
|
title: Some(post.title.to_string()),
|
||||||
|
link: Some(utils::get_post_url(&post)),
|
||||||
|
author: Some(post.author.name),
|
||||||
|
content: Some(rewrite_urls(&post.body)),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Serialize the feed to RSS
|
||||||
|
let body = channel.to_string().into_bytes();
|
||||||
|
|
||||||
|
// Create the HTTP response
|
||||||
|
let mut res = Response::new(Body::from(body));
|
||||||
|
res.headers_mut().insert(CONTENT_TYPE, hyper::header::HeaderValue::from_static("application/rss+xml"));
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn test_fetching_user() {
|
async fn test_fetching_user() {
|
||||||
let user = user("spez").await;
|
let user = user("spez").await;
|
||||||
|
30
src/utils.rs
30
src/utils.rs
@ -1,5 +1,5 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use crate::config::get_setting;
|
use crate::config::{self, get_setting};
|
||||||
//
|
//
|
||||||
// CRATES
|
// CRATES
|
||||||
//
|
//
|
||||||
@ -15,6 +15,7 @@ use serde_json::Value;
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::string::ToString;
|
||||||
use time::{macros::format_description, Duration, OffsetDateTime};
|
use time::{macros::format_description, Duration, OffsetDateTime};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -327,6 +328,7 @@ pub struct Post {
|
|||||||
pub gallery: Vec<GalleryMedia>,
|
pub gallery: Vec<GalleryMedia>,
|
||||||
pub awards: Awards,
|
pub awards: Awards,
|
||||||
pub nsfw: bool,
|
pub nsfw: bool,
|
||||||
|
pub out_url: Option<String>,
|
||||||
pub ws_url: String,
|
pub ws_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,6 +437,7 @@ impl Post {
|
|||||||
awards,
|
awards,
|
||||||
nsfw: post["data"]["over_18"].as_bool().unwrap_or_default(),
|
nsfw: post["data"]["over_18"].as_bool().unwrap_or_default(),
|
||||||
ws_url: val(post, "websocket_url"),
|
ws_url: val(post, "websocket_url"),
|
||||||
|
out_url: post["data"]["url_overridden_by_dest"].as_str().map(|a| a.to_string()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok((posts, res["data"]["after"].as_str().unwrap_or_default().to_string()))
|
Ok((posts, res["data"]["after"].as_str().unwrap_or_default().to_string()))
|
||||||
@ -770,6 +773,7 @@ pub async fn parse_post(post: &Value) -> Post {
|
|||||||
awards,
|
awards,
|
||||||
nsfw: post["data"]["over_18"].as_bool().unwrap_or_default(),
|
nsfw: post["data"]["over_18"].as_bool().unwrap_or_default(),
|
||||||
ws_url: val(post, "websocket_url"),
|
ws_url: val(post, "websocket_url"),
|
||||||
|
out_url: post["data"]["url_overridden_by_dest"].as_str().map(|a| a.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1082,6 +1086,16 @@ pub fn sfw_only() -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the config/env variable REDLIB_ENABLE_RSS is set to "on".
|
||||||
|
/// If this variable is set as such, the instance will enable RSS feeds.
|
||||||
|
/// Otherwise, the instance will not provide RSS feeds.
|
||||||
|
pub fn enable_rss() -> bool {
|
||||||
|
match get_setting("REDLIB_ENABLE_RSS") {
|
||||||
|
Some(val) => val == "on",
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Determines if a request shoud redirect to a nsfw landing gate.
|
// Determines if a request shoud redirect to a nsfw landing gate.
|
||||||
pub fn should_be_nsfw_gated(req: &Request<Body>, req_url: &str) -> bool {
|
pub fn should_be_nsfw_gated(req: &Request<Body>, req_url: &str) -> bool {
|
||||||
let sfw_instance = sfw_only();
|
let sfw_instance = sfw_only();
|
||||||
@ -1137,6 +1151,20 @@ pub fn url_path_basename(path: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the URL of a post, as needed by RSS feeds
|
||||||
|
pub fn get_post_url(post: &Post) -> String {
|
||||||
|
if let Some(out_url) = &post.out_url {
|
||||||
|
// Handle cross post
|
||||||
|
if out_url.starts_with("/r/") {
|
||||||
|
format!("{}{}", config::get_setting("REDLIB_FULL_URL").unwrap_or_default(), out_url)
|
||||||
|
} else {
|
||||||
|
out_url.to_string()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format!("{}{}", config::get_setting("REDLIB_FULL_URL").unwrap_or_default(), post.permalink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{format_num, format_url, rewrite_urls};
|
use super::{format_num, format_url, rewrite_urls};
|
||||||
|
2272
static/style.css
2272
static/style.css
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@
|
|||||||
{% call utils::sort(["/r/", sub.name.as_str()].concat(), ["hot", "new", "top", "rising", "controversial"], sort.0) %}
|
{% call utils::sort(["/r/", sub.name.as_str()].concat(), ["hot", "new", "top", "rising", "controversial"], sort.0) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if sort.0 == "top" || sort.0 == "controversial" %}<select id="timeframe" name="t" title="Timeframe">
|
{% if sort.0 == "top" || sort.0 == "controversial" %}<select id="timeframe" name="t" title="Timeframe">
|
||||||
{% call utils::options(sort.1, ["hour", "day", "week", "month", "year", "all"], "day") %}
|
{% call utils::options(sort.1, ["hour", "day", "week", "month", "year", "all"], "day") %}
|
||||||
</select>
|
</select>
|
||||||
<button id="sort_submit" class="submit">
|
<button id="sort_submit" class="submit">
|
||||||
@ -130,7 +130,13 @@
|
|||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% if crate::utils::enable_rss() %}
|
||||||
|
<div id="sub_rss">
|
||||||
|
<a href="/r/{{ sub.name }}.rss" title="RSS feed for r/{{ sub.name }}">
|
||||||
|
<button class="subscribe">RSS feed</button >
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
<details class="panel" id="sidebar">
|
<details class="panel" id="sidebar">
|
||||||
|
@ -1,140 +1,178 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %} {% import "utils.html" as utils %} {% block search %}
|
||||||
{% import "utils.html" as utils %}
|
{% call utils::search("".to_owned(), "") %} {% endblock %} {% block title %}{{
|
||||||
|
user.name.replace("u/", "") }} (u/{{ user.name }}) - Redlib{% endblock %} {%
|
||||||
|
block subscriptions %} {% call utils::sub_list("") %} {% endblock %} {% block
|
||||||
|
body %}
|
||||||
|
<main>
|
||||||
|
{% if !is_filtered %}
|
||||||
|
<div id="column_one">
|
||||||
|
<form id="sort">
|
||||||
|
<div id="listing_options">
|
||||||
|
{% call utils::sort(["/user/", user.name.as_str()].concat(),
|
||||||
|
["overview", "comments", "submitted"], listing) %}
|
||||||
|
</div>
|
||||||
|
<select id="sort_select" name="sort">
|
||||||
|
{% call utils::options(sort.0, ["hot", "new", "top",
|
||||||
|
"controversial"], "") %}</select
|
||||||
|
>{% if sort.0 == "top" || sort.0 == "controversial" %}<select
|
||||||
|
id="timeframe"
|
||||||
|
name="t"
|
||||||
|
>
|
||||||
|
{% call utils::options(sort.1, ["hour", "day", "week", "month",
|
||||||
|
"year", "all"], "all") %}</select
|
||||||
|
>{% endif %}<button id="sort_submit" class="submit">
|
||||||
|
<svg
|
||||||
|
width="15"
|
||||||
|
viewBox="0 0 110 100"
|
||||||
|
fill="none"
|
||||||
|
stroke-width="10"
|
||||||
|
stroke-linecap="round"
|
||||||
|
>
|
||||||
|
<path d="M20 50 H100" />
|
||||||
|
<path d="M75 15 L100 50 L75 85" />
|
||||||
|
→
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
{% block search %}
|
{% if all_posts_hidden_nsfw %}
|
||||||
{% call utils::search("".to_owned(), "") %}
|
<center>
|
||||||
{% endblock %}
|
All posts are hidden because they are NSFW. Enable "Show NSFW posts"
|
||||||
|
in settings to view.
|
||||||
{% block title %}{{ user.name.replace("u/", "") }} (u/{{ user.name }}) - Redlib{% endblock %}
|
</center>
|
||||||
|
{% endif %} {% if no_posts %}
|
||||||
{% block subscriptions %}
|
<center>No posts were found.</center>
|
||||||
{% call utils::sub_list("") %}
|
{% endif %} {% if all_posts_filtered %}
|
||||||
{% endblock %}
|
<center>(All content on this page has been filtered)</center>
|
||||||
|
{% else %}
|
||||||
{% block body %}
|
<div id="posts">
|
||||||
<main>
|
{% for post in posts %} {% if post.flags.nsfw && prefs.show_nsfw !=
|
||||||
{% if !is_filtered %}
|
"on" %} {% else if !post.title.is_empty() %} {% call
|
||||||
<div id="column_one">
|
utils::post_in_list(post) %} {% else %}
|
||||||
<form id="sort">
|
<div class="comment user-comment">
|
||||||
<div id="listing_options">
|
<div class="comment_left">
|
||||||
{% call utils::sort(["/user/", user.name.as_str()].concat(), ["overview", "comments", "submitted"], listing) %}
|
<p class="comment_score" title="{{ post.score.1 }}">
|
||||||
</div>
|
{% if prefs.hide_score != "on" %} {{ post.score.0 }} {%
|
||||||
<select id="sort_select" name="sort">
|
else %} • {% endif %}
|
||||||
{% call utils::options(sort.0, ["hot", "new", "top", "controversial"], "") %}
|
|
||||||
</select>{% if sort.0 == "top" || sort.0 == "controversial" %}<select id="timeframe" name="t">
|
|
||||||
{% call utils::options(sort.1, ["hour", "day", "week", "month", "year", "all"], "all") %}
|
|
||||||
</select>{% endif %}<button id="sort_submit" class="submit">
|
|
||||||
<svg width="15" viewBox="0 0 110 100" fill="none" stroke-width="10" stroke-linecap="round">
|
|
||||||
<path d="M20 50 H100" />
|
|
||||||
<path d="M75 15 L100 50 L75 85" />
|
|
||||||
→
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% if all_posts_hidden_nsfw %}
|
|
||||||
<center>All posts are hidden because they are NSFW. Enable "Show NSFW posts" in settings to view.</center>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if no_posts %}
|
|
||||||
<center>No posts were found.</center>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if all_posts_filtered %}
|
|
||||||
<center>(All content on this page has been filtered)</center>
|
|
||||||
{% else %}
|
|
||||||
<div id="posts">
|
|
||||||
{% for post in posts %}
|
|
||||||
|
|
||||||
{% if post.flags.nsfw && prefs.show_nsfw != "on" %}
|
|
||||||
{% else if !post.title.is_empty() %}
|
|
||||||
{% call utils::post_in_list(post) %}
|
|
||||||
{% else %}
|
|
||||||
<div class="comment user-comment">
|
|
||||||
<div class="comment_left">
|
|
||||||
<p class="comment_score" title="{{ post.score.1 }}">
|
|
||||||
{% if prefs.hide_score != "on" %}
|
|
||||||
{{ post.score.0 }}
|
|
||||||
{% else %}
|
|
||||||
•
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
</p>
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
</div>
|
</div>
|
||||||
<details class="comment_right" open>
|
<details class="comment_right" open>
|
||||||
<summary class="comment_data">
|
<summary class="comment_data">
|
||||||
<a class="comment_link" href="{{ post.permalink }}" title="{{ post.link_title }}">{{ post.link_title }}</a>
|
<a
|
||||||
<div class="user_comment_data_divider">
|
class="comment_link"
|
||||||
<span class="created-in"> in </span>
|
href="{{ post.permalink }}"
|
||||||
<a class="comment_subreddit" href="/r/{{ post.community }}">r/{{ post.community }}</a>
|
title="{{ post.link_title }}"
|
||||||
<span class="dot">•</span>
|
>{{ post.link_title }}</a
|
||||||
<span class="created" title="{{ post.created }}"> {{ post.rel_time }}</span>
|
>
|
||||||
</div>
|
<div class="user_comment_data_divider">
|
||||||
</summary>
|
<span class="created-in"> in </span>
|
||||||
<p class="comment_body">{{ post.body|safe }}</p>
|
<a
|
||||||
</details>
|
class="comment_subreddit"
|
||||||
</div>
|
href="/r/{{ post.community }}"
|
||||||
{% endif %}
|
>r/{{ post.community }}</a
|
||||||
{% endfor %}
|
>
|
||||||
{% if prefs.use_hls == "on" %}
|
<span class="dot">•</span>
|
||||||
<script src="/hls.min.js"></script>
|
<span class="created" title="{{ post.created }}"
|
||||||
<script src="/playHLSVideo.js"></script>
|
> {{ post.rel_time }}</span
|
||||||
{% endif %}
|
>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
</summary>
|
||||||
|
<p class="comment_body">{{ post.body|safe }}</p>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
{% endif %} {% endfor %} {% if prefs.use_hls == "on" %}
|
||||||
|
<script src="/hls.min.js"></script>
|
||||||
|
<script src="/playHLSVideo.js"></script>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
{% if ends.0 != "" %}
|
{% if ends.0 != "" %}
|
||||||
<a href="?sort={{ sort.0 }}&t={{ sort.1 }}&before={{ ends.0 }}" accesskey="P">PREV</a>
|
<a
|
||||||
{% endif %}
|
href="?sort={{ sort.0 }}&t={{ sort.1 }}&before={{ ends.0 }}"
|
||||||
|
accesskey="P"
|
||||||
{% if ends.1 != "" %}
|
>PREV</a
|
||||||
<a href="?sort={{ sort.0 }}&t={{ sort.1 }}&after={{ ends.1 }}" accesskey="N">NEXT</a>
|
>
|
||||||
{% endif %}
|
{% endif %} {% if ends.1 != "" %}
|
||||||
</footer>
|
<a
|
||||||
</div>
|
href="?sort={{ sort.0 }}&t={{ sort.1 }}&after={{ ends.1 }}"
|
||||||
{% endif %}
|
accesskey="N"
|
||||||
<aside>
|
>NEXT</a
|
||||||
{% if is_filtered %}
|
>
|
||||||
<center>(Content from u/{{ user.name }} has been filtered)</center>
|
{% endif %}
|
||||||
{% endif %}
|
</footer>
|
||||||
<div class="panel" id="user">
|
</div>
|
||||||
<img loading="lazy" id="user_icon" src="{{ user.icon }}" alt="User icon">
|
{% endif %}
|
||||||
<h1 id="user_title">{{ user.title }}</h1>
|
<aside>
|
||||||
<p id="user_name">u/{{ user.name }}</p>
|
{% if is_filtered %}
|
||||||
<div id="user_description">{{ user.description }}</div>
|
<center>(Content from u/{{ user.name }} has been filtered)</center>
|
||||||
<div id="user_details">
|
{% endif %}
|
||||||
<label>Karma</label>
|
<div class="panel" id="user">
|
||||||
<label>Created</label>
|
<img
|
||||||
<div>{{ user.karma }}</div>
|
loading="lazy"
|
||||||
<div>{{ user.created }}</div>
|
id="user_icon"
|
||||||
</div>
|
src="{{ user.icon }}"
|
||||||
<div id="user_actions">
|
alt="User icon"
|
||||||
{% let name = ["u_", user.name.as_str()].join("") %}
|
/>
|
||||||
<div id="user_subscription">
|
<h1 id="user_title">{{ user.title }}</h1>
|
||||||
{% if prefs.subscriptions.contains(name) %}
|
<p id="user_name">u/{{ user.name }}</p>
|
||||||
<form action="/r/{{ name }}/unsubscribe?redirect={{ redirect_url }}" method="POST">
|
<div id="user_description">{{ user.description }}</div>
|
||||||
<button class="unsubscribe">Unfollow</button>
|
<div id="user_details">
|
||||||
</form>
|
<label>Karma</label>
|
||||||
{% else %}
|
<label>Created</label>
|
||||||
<form action="/r/{{ name }}/subscribe?redirect={{ redirect_url }}" method="POST">
|
<div>{{ user.karma }}</div>
|
||||||
<button class="subscribe">Follow</button>
|
<div>{{ user.created }}</div>
|
||||||
</form>
|
</div>
|
||||||
{% endif %}
|
<div id="user_actions">
|
||||||
</div>
|
{% let name = ["u_", user.name.as_str()].join("") %}
|
||||||
<div id="user_filter">
|
<div id="user_subscription">
|
||||||
{% if prefs.filters.contains(name) %}
|
{% if prefs.subscriptions.contains(name) %}
|
||||||
<form action="/r/{{ name }}/unfilter?redirect={{ redirect_url }}" method="POST">
|
<form
|
||||||
<button class="unfilter">Unfilter</button>
|
action="/r/{{ name }}/unsubscribe?redirect={{ redirect_url }}"
|
||||||
</form>
|
method="POST"
|
||||||
{% else %}
|
>
|
||||||
<form action="/r/{{ name }}/filter?redirect={{ redirect_url }}" method="POST">
|
<button class="unsubscribe">Unfollow</button>
|
||||||
<button class="filter">Filter</button>
|
</form>
|
||||||
</form>
|
{% else %}
|
||||||
{% endif %}
|
<form
|
||||||
</div>
|
action="/r/{{ name }}/subscribe?redirect={{ redirect_url }}"
|
||||||
</div>
|
method="POST"
|
||||||
</div>
|
>
|
||||||
</aside>
|
<button class="subscribe">Follow</button>
|
||||||
</main>
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div id="user_filter">
|
||||||
|
{% if prefs.filters.contains(name) %}
|
||||||
|
<form
|
||||||
|
action="/r/{{ name }}/unfilter?redirect={{ redirect_url }}"
|
||||||
|
method="POST"
|
||||||
|
>
|
||||||
|
<button class="unfilter">Unfilter</button>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<form
|
||||||
|
action="/r/{{ name }}/filter?redirect={{ redirect_url }}"
|
||||||
|
method="POST"
|
||||||
|
>
|
||||||
|
<button class="filter">Filter</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if crate::utils::enable_rss() %}
|
||||||
|
<div id="user_rss">
|
||||||
|
<a
|
||||||
|
href="/u/{{ user.name }}.rss"
|
||||||
|
title="RSS feed for u/{{ user.name }}"
|
||||||
|
>
|
||||||
|
<button class="subscribe">RSS feed</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
Reference in New Issue
Block a user