commit
5030c418de
181
Cargo.lock
generated
181
Cargo.lock
generated
@ -346,15 +346,6 @@ dependencies = [
|
|||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-mutex"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
|
|
||||||
dependencies = [
|
|
||||||
"event-listener",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-recursion"
|
name = "async-recursion"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -489,9 +480,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.5.0"
|
version = "3.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f07aa6688c702439a1be0307b6a94dffe1168569e45b9500c1372bc580740d59"
|
checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
@ -520,40 +511,6 @@ dependencies = [
|
|||||||
"bytes 1.0.1",
|
"bytes 1.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cached"
|
|
||||||
version = "0.23.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5e2afe73808fbaac302e39c9754bfc3c4b4d0f99c9c240b9f4e4efc841ad1b74"
|
|
||||||
dependencies = [
|
|
||||||
"async-mutex",
|
|
||||||
"async-trait",
|
|
||||||
"cached_proc_macro",
|
|
||||||
"cached_proc_macro_types",
|
|
||||||
"futures",
|
|
||||||
"hashbrown",
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cached_proc_macro"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bf857ae42d910aede5c5186e62684b0d7a597ce2fe3bd14448ab8f7ef439848c"
|
|
||||||
dependencies = [
|
|
||||||
"async-mutex",
|
|
||||||
"cached_proc_macro_types",
|
|
||||||
"darling",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cached_proc_macro_types"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.66"
|
version = "1.0.66"
|
||||||
@ -574,9 +531,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chunked_transfer"
|
name = "chunked_transfer"
|
||||||
version = "1.3.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca"
|
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const_fn"
|
name = "const_fn"
|
||||||
@ -616,41 +573,6 @@ dependencies = [
|
|||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling"
|
|
||||||
version = "0.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
|
|
||||||
dependencies = [
|
|
||||||
"darling_core",
|
|
||||||
"darling_macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling_core"
|
|
||||||
version = "0.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
|
|
||||||
dependencies = [
|
|
||||||
"fnv",
|
|
||||||
"ident_case",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"strsim",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling_macro"
|
|
||||||
version = "0.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
|
|
||||||
dependencies = [
|
|
||||||
"darling_core",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "0.99.11"
|
version = "0.99.11"
|
||||||
@ -704,17 +626,11 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "event-listener"
|
|
||||||
version = "2.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.19"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129"
|
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
@ -969,12 +885,6 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e"
|
checksum = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ident_case"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -1034,9 +944,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.46"
|
version = "0.3.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175"
|
checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@ -1078,19 +988,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.82"
|
version = "0.2.84"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
|
checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libreddit"
|
name = "libreddit"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"askama",
|
"askama",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"base64 0.13.0",
|
"base64 0.13.0",
|
||||||
"cached",
|
|
||||||
"futures",
|
"futures",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1117,11 +1026,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.13"
|
version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2"
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1222,9 +1131,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "6.0.1"
|
version = "6.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88034cfd6b4a0d54dd14f4a507eceee36c0b70e5a02236c4e4df571102be17f0"
|
checksum = "ab6f70b46d6325aa300f1c7bb3d470127dfc27806d8ea6bf294ee0ce643ce2b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"lexical-core",
|
"lexical-core",
|
||||||
@ -1576,18 +1485,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.120"
|
version = "1.0.123"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "166b2349061381baf54a58e4b13c89369feb0ef2eaa57198899e2312aac30aab"
|
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.120"
|
version = "1.0.123"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ca2a8cb5805ce9e3b95435e3765b7b553cecc762d938d409434338386cb5775"
|
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1738,17 +1647,11 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strsim"
|
|
||||||
version = "0.9.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.59"
|
version = "1.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07cb8b1b4ebf86a89ee88cbd201b022b94138c623644d035185c84d3f41b7e66"
|
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1783,9 +1686,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.1.1"
|
version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "301bdd13d23c49672926be451130892d274d3ba0b410c18e00daa7990ff38d99"
|
checksum = "d8208a331e1cb318dd5bd76951d2b8fc48ca38a69f5f4e4af1b6a9f8c6236915"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
@ -1801,9 +1704,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.2.24"
|
version = "0.2.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "273d3ed44dca264b0d6b3665e8d48fb515042d42466fad93d2a45b90ec4058f7"
|
checksum = "1195b046942c221454c2539395f85413b33383a067449d78aab2b7b052a142f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_fn",
|
"const_fn",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1839,9 +1742,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.1.0"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f"
|
checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tinyvec_macros",
|
"tinyvec_macros",
|
||||||
]
|
]
|
||||||
@ -1854,9 +1757,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "0.2.24"
|
version = "0.2.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48"
|
checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.5.6",
|
"bytes 0.5.6",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -2062,9 +1965,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
|
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
@ -2072,9 +1975,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
|
checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -2087,9 +1990,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
|
checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@ -2097,9 +2000,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
|
checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2110,15 +2013,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
|
checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.46"
|
version = "0.3.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3"
|
checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
@ -3,7 +3,7 @@ name = "libreddit"
|
|||||||
description = " Alternative private front-end to Reddit"
|
description = " Alternative private front-end to Reddit"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
repository = "https://github.com/spikecodes/libreddit"
|
repository = "https://github.com/spikecodes/libreddit"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@ -12,11 +12,10 @@ base64 = "0.13"
|
|||||||
actix-web = { version = "3.3", features = ["rustls"] }
|
actix-web = { version = "3.3", features = ["rustls"] }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
askama = "0.10"
|
askama = "0.10"
|
||||||
ureq = "2.0"
|
ureq = "2"
|
||||||
serde = { version = "1.0", default_features = false, features = ["derive"] }
|
serde = { version = "1.0", default_features = false, features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
async-recursion = "0.3"
|
async-recursion = "0.3"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
regex = "1.4"
|
regex = "1.4"
|
||||||
time = "0.2"
|
time = "0.2"
|
||||||
cached = "0.23.0"
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
> An alternative private front-end to Reddit
|
> An alternative private front-end to Reddit
|
||||||
|
|
||||||
![screenshot](https://i.ibb.co/FxxbKM6/libreddit-rust.png)
|
![screenshot](https://i.ibb.co/F0JsY5K/image.png)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -40,7 +40,9 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new)
|
|||||||
| [libreddit.dothq.co](https://libreddit.dothq.co) | 🇺🇸 US | ✅ |
|
| [libreddit.dothq.co](https://libreddit.dothq.co) | 🇺🇸 US | ✅ |
|
||||||
| [libreddit.insanity.wtf](https://libreddit.insanity.wtf) | 🇺🇸 US | ✅ |
|
| [libreddit.insanity.wtf](https://libreddit.insanity.wtf) | 🇺🇸 US | ✅ |
|
||||||
| [libreddit.kavin.rocks](https://libreddit.kavin.rocks) | 🇮🇳 IN | ✅ |
|
| [libreddit.kavin.rocks](https://libreddit.kavin.rocks) | 🇮🇳 IN | ✅ |
|
||||||
|
| [libreddit.himiko.cloud](https://libreddit.himiko.cloud) | 🇧🇬 BG | |
|
||||||
| [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | 🇮🇳 IN | |
|
| [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | 🇮🇳 IN | |
|
||||||
|
| [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | 🇩🇪 DE | |
|
||||||
|
|
||||||
A checkmark in the "Cloudflare" category here refers to the use of the reverse proxy, [Cloudflare](https://cloudflare). The checkmark will not be listed for a site which uses Cloudflare DNS but rather the proxying service which grants Cloudflare the ability to monitor traffic to the website.
|
A checkmark in the "Cloudflare" category here refers to the use of the reverse proxy, [Cloudflare](https://cloudflare). The checkmark will not be listed for a site which uses Cloudflare DNS but rather the proxying service which grants Cloudflare the ability to monitor traffic to the website.
|
||||||
|
|
||||||
@ -123,7 +125,7 @@ Results from Google Lighthouse ([Libreddit Report](https://lighthouse-dot-webdot
|
|||||||
|
|
||||||
For transparency, I hope to describe all the ways Libreddit handles user privacy.
|
For transparency, I hope to describe all the ways Libreddit handles user privacy.
|
||||||
|
|
||||||
**Logging:** In production (when running the binary, hosting with docker, or using the official instances), Libreddit logs nothing. When debugging (running from source without `--release`), Libreddit logs post IDs and URL paths fetched to aid with troubleshooting.
|
**Logging:** In production (when running the binary, hosting with docker, or using the official instances), Libreddit logs when Reddit is ratelimiting Libreddit and when Reddit's JSON responses can't be parsed. When debugging (running from source without `--release`), Libreddit logs post IDs and URL paths fetched to aid with troubleshooting.
|
||||||
|
|
||||||
**DNS:** Both official domains (`libredd.it` and `libreddit.spike.codes`) use Cloudflare as the DNS resolver. Though, the sites are not proxied through Cloudflare meaning Cloudflare doesn't have access to user traffic.
|
**DNS:** Both official domains (`libredd.it` and `libreddit.spike.codes`) use Cloudflare as the DNS resolver. Though, the sites are not proxied through Cloudflare meaning Cloudflare doesn't have access to user traffic.
|
||||||
|
|
||||||
|
36
src/main.rs
36
src/main.rs
@ -19,6 +19,21 @@ async fn style() -> HttpResponse {
|
|||||||
HttpResponse::Ok().content_type("text/css").body(include_str!("../static/style.css"))
|
HttpResponse::Ok().content_type("text/css").body(include_str!("../static/style.css"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Required for creating a PWA
|
||||||
|
async fn manifest() -> HttpResponse {
|
||||||
|
HttpResponse::Ok().content_type("application/json").body(include_str!("../static/manifest.json"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required for the manifest to be valid
|
||||||
|
async fn pwa_logo() -> HttpResponse {
|
||||||
|
HttpResponse::Ok().content_type("image/png").body(include_bytes!("../static/logo.png").as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required for iOS App Icons
|
||||||
|
async fn iphone_logo() -> HttpResponse {
|
||||||
|
HttpResponse::Ok().content_type("image/png").body(include_bytes!("../static/touch-icon-iphone.png").as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
async fn robots() -> HttpResponse {
|
async fn robots() -> HttpResponse {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.header("Cache-Control", "public, max-age=1209600, s-maxage=86400")
|
.header("Cache-Control", "public, max-age=1209600, s-maxage=86400")
|
||||||
@ -27,6 +42,7 @@ async fn robots() -> HttpResponse {
|
|||||||
|
|
||||||
async fn favicon() -> HttpResponse {
|
async fn favicon() -> HttpResponse {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
|
.content_type("image/x-icon")
|
||||||
.header("Cache-Control", "public, max-age=1209600, s-maxage=86400")
|
.header("Cache-Control", "public, max-age=1209600, s-maxage=86400")
|
||||||
.body(include_bytes!("../static/favicon.ico").as_ref())
|
.body(include_bytes!("../static/favicon.ico").as_ref())
|
||||||
}
|
}
|
||||||
@ -53,7 +69,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.wrap_fn(move |req, srv| {
|
.wrap_fn(move |req, srv| {
|
||||||
let secure = req.connection_info().scheme() == "https";
|
let secure = req.connection_info().scheme() == "https";
|
||||||
let https_url = format!("https://{}{}", req.connection_info().host(), req.uri().to_string());
|
let https_url = format!("https://{}{}", req.connection_info().host(), req.uri().to_string());
|
||||||
srv.call(req).map(move |res: Result<ServiceResponse, _>|
|
srv.call(req).map(move |res: Result<ServiceResponse, _>| {
|
||||||
if force_https && !secure {
|
if force_https && !secure {
|
||||||
Ok(ServiceResponse::new(
|
Ok(ServiceResponse::new(
|
||||||
res.unwrap().request().to_owned(),
|
res.unwrap().request().to_owned(),
|
||||||
@ -62,16 +78,30 @@ async fn main() -> std::io::Result<()> {
|
|||||||
} else {
|
} else {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
})
|
})
|
||||||
// Append trailing slash and remove double slashes
|
// Append trailing slash and remove double slashes
|
||||||
.wrap(middleware::NormalizePath::default())
|
.wrap(middleware::NormalizePath::default())
|
||||||
|
// Apply default headers for security
|
||||||
|
.wrap(
|
||||||
|
middleware::DefaultHeaders::new()
|
||||||
|
.header("Referrer-Policy", "no-referrer")
|
||||||
|
.header("X-Content-Type-Options", "nosniff")
|
||||||
|
.header("X-Frame-Options", "DENY")
|
||||||
|
.header(
|
||||||
|
"Content-Security-Policy",
|
||||||
|
"default-src 'none'; manifest-src 'self'; media-src 'self'; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none';",
|
||||||
|
),
|
||||||
|
)
|
||||||
// Default service in case no routes match
|
// Default service in case no routes match
|
||||||
.default_service(web::get().to(|| utils::error("Nothing here".to_string())))
|
.default_service(web::get().to(|| utils::error("Nothing here".to_string())))
|
||||||
// Read static files
|
// Read static files
|
||||||
.route("/style.css/", web::get().to(style))
|
.route("/style.css/", web::get().to(style))
|
||||||
.route("/favicon.ico/", web::get().to(favicon))
|
.route("/favicon.ico/", web::get().to(favicon))
|
||||||
.route("/robots.txt/", web::get().to(robots))
|
.route("/robots.txt/", web::get().to(robots))
|
||||||
|
.route("/manifest.json/", web::get().to(manifest))
|
||||||
|
.route("/logo.png/", web::get().to(pwa_logo))
|
||||||
|
.route("/touch-icon-iphone.png/", web::get().to(iphone_logo))
|
||||||
// Proxy media through Libreddit
|
// Proxy media through Libreddit
|
||||||
.route("/proxy/{url:.*}/", web::get().to(proxy::handler))
|
.route("/proxy/{url:.*}/", web::get().to(proxy::handler))
|
||||||
// Browse user profile
|
// Browse user profile
|
||||||
@ -92,6 +122,8 @@ async fn main() -> std::io::Result<()> {
|
|||||||
// See posts and info about subreddit
|
// See posts and info about subreddit
|
||||||
.route("/", web::get().to(subreddit::page))
|
.route("/", web::get().to(subreddit::page))
|
||||||
.route("/{sort:hot|new|top|rising|controversial}/", web::get().to(subreddit::page))
|
.route("/{sort:hot|new|top|rising|controversial}/", web::get().to(subreddit::page))
|
||||||
|
// Handle subscribe/unsubscribe
|
||||||
|
.route("/{action:subscribe|unsubscribe}/", web::post().to(subreddit::subscriptions))
|
||||||
// View post on subreddit
|
// View post on subreddit
|
||||||
.service(
|
.service(
|
||||||
web::scope("/comments/{id}/{title}")
|
web::scope("/comments/{id}/{title}")
|
||||||
|
@ -171,7 +171,11 @@ async fn parse_comments(json: &serde_json::Value) -> Vec<Comment> {
|
|||||||
},
|
},
|
||||||
distinguished: val(&comment, "distinguished"),
|
distinguished: val(&comment, "distinguished"),
|
||||||
},
|
},
|
||||||
score: format_num(score),
|
score: if comment["data"]["score_hidden"].as_bool().unwrap_or_default() {
|
||||||
|
"•".to_string()
|
||||||
|
} else {
|
||||||
|
format_num(score)
|
||||||
|
},
|
||||||
rel_time,
|
rel_time,
|
||||||
created,
|
created,
|
||||||
replies,
|
replies,
|
||||||
|
10
src/proxy.rs
10
src/proxy.rs
@ -21,11 +21,10 @@ pub async fn handler(web::Path(b64): web::Path<String>) -> Result<HttpResponse>
|
|||||||
"v.redd.it",
|
"v.redd.it",
|
||||||
];
|
];
|
||||||
|
|
||||||
match decode(b64) {
|
let decoded = decode(b64).map(|bytes| String::from_utf8(bytes).unwrap_or_default());
|
||||||
Ok(bytes) => {
|
|
||||||
let media = String::from_utf8(bytes).unwrap_or_default();
|
|
||||||
|
|
||||||
match Url::parse(media.as_str()) {
|
match decoded {
|
||||||
|
Ok(media) => match Url::parse(media.as_str()) {
|
||||||
Ok(url) => {
|
Ok(url) => {
|
||||||
let domain = url.domain().unwrap_or_default();
|
let domain = url.domain().unwrap_or_default();
|
||||||
|
|
||||||
@ -42,8 +41,7 @@ pub async fn handler(web::Path(b64): web::Path<String>) -> Result<HttpResponse>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err(error::ErrorBadRequest("Can't parse base64 into URL")),
|
_ => Err(error::ErrorBadRequest("Can't parse base64 into URL")),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
_ => Err(error::ErrorBadRequest("Can't decode base64")),
|
_ => Err(error::ErrorBadRequest("Can't decode base64")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ struct SearchTemplate {
|
|||||||
|
|
||||||
// SERVICES
|
// SERVICES
|
||||||
pub async fn find(req: HttpRequest) -> HttpResponse {
|
pub async fn find(req: HttpRequest) -> HttpResponse {
|
||||||
let nsfw_results = if cookie(&req, "hide_nsfw") != "on" { "&include_over_18=on" } else { "" };
|
let nsfw_results = if cookie(&req, "show_nsfw") == "on" { "&include_over_18=on" } else { "" };
|
||||||
let path = format!("{}.json?{}{}", req.path(), req.query_string(), nsfw_results);
|
let path = format!("{}.json?{}{}", req.path(), req.query_string(), nsfw_results);
|
||||||
let sub = req.match_info().get("sub").unwrap_or("").to_string();
|
let sub = req.match_info().get("sub").unwrap_or("").to_string();
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ pub struct SettingsForm {
|
|||||||
layout: Option<String>,
|
layout: Option<String>,
|
||||||
wide: Option<String>,
|
wide: Option<String>,
|
||||||
comment_sort: Option<String>,
|
comment_sort: Option<String>,
|
||||||
hide_nsfw: Option<String>,
|
show_nsfw: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTIONS
|
// FUNCTIONS
|
||||||
@ -33,8 +33,8 @@ pub async fn get(req: HttpRequest) -> HttpResponse {
|
|||||||
pub async fn set(_req: HttpRequest, form: Form<SettingsForm>) -> HttpResponse {
|
pub async fn set(_req: HttpRequest, form: Form<SettingsForm>) -> HttpResponse {
|
||||||
let mut res = HttpResponse::Found();
|
let mut res = HttpResponse::Found();
|
||||||
|
|
||||||
let names = vec!["theme", "front_page", "layout", "wide", "comment_sort", "hide_nsfw"];
|
let names = vec!["theme", "front_page", "layout", "wide", "comment_sort", "show_nsfw"];
|
||||||
let values = vec![&form.theme, &form.front_page, &form.layout, &form.wide, &form.comment_sort, &form.hide_nsfw];
|
let values = vec![&form.theme, &form.front_page, &form.layout, &form.wide, &form.comment_sort, &form.show_nsfw];
|
||||||
|
|
||||||
for (i, name) in names.iter().enumerate() {
|
for (i, name) in names.iter().enumerate() {
|
||||||
match values[i] {
|
match values[i] {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
// CRATES
|
// CRATES
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
use actix_web::{HttpRequest, HttpResponse, Result};
|
use actix_web::{cookie::Cookie, HttpRequest, HttpResponse, Result};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
use time::{Duration, OffsetDateTime};
|
||||||
|
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
@ -25,23 +26,43 @@ struct WikiTemplate {
|
|||||||
|
|
||||||
// SERVICES
|
// SERVICES
|
||||||
pub async fn page(req: HttpRequest) -> HttpResponse {
|
pub async fn page(req: HttpRequest) -> HttpResponse {
|
||||||
let path = format!("{}.json?{}", req.path(), req.query_string());
|
let subscribed = cookie(&req, "subscriptions");
|
||||||
let default = cookie(&req, "front_page");
|
let front_page = cookie(&req, "front_page");
|
||||||
let sub_name = req
|
let sort = req.match_info().get("sort").unwrap_or("hot").to_string();
|
||||||
|
|
||||||
|
let sub = req
|
||||||
.match_info()
|
.match_info()
|
||||||
.get("sub")
|
.get("sub")
|
||||||
.unwrap_or(if default.is_empty() { "popular" } else { default.as_str() })
|
.map(String::from)
|
||||||
.to_string();
|
.unwrap_or(if front_page == "default" || front_page.is_empty() {
|
||||||
let sort = req.match_info().get("sort").unwrap_or("hot").to_string();
|
if subscribed.is_empty() {
|
||||||
|
"popular".to_string()
|
||||||
|
} else {
|
||||||
|
subscribed.to_owned()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
front_page.to_owned()
|
||||||
|
});
|
||||||
|
|
||||||
|
let path = format!("/r/{}/{}.json?{}", sub, sort, req.query_string());
|
||||||
|
|
||||||
match fetch_posts(&path, String::new()).await {
|
match fetch_posts(&path, String::new()).await {
|
||||||
Ok((posts, after)) => {
|
Ok((posts, after)) => {
|
||||||
// If you can get subreddit posts, also request subreddit metadata
|
// If you can get subreddit posts, also request subreddit metadata
|
||||||
let sub = if !sub_name.contains('+') && sub_name != "popular" && sub_name != "all" {
|
let sub = if !sub.contains('+') && sub != subscribed && sub != "popular" && sub != "all" {
|
||||||
subreddit(&sub_name).await.unwrap_or_default()
|
// Regular subreddit
|
||||||
} else if sub_name.contains('+') {
|
subreddit(&sub).await.unwrap_or_default()
|
||||||
|
} else if sub == subscribed {
|
||||||
|
// Subscription feed
|
||||||
|
if req.path().starts_with("/r/") {
|
||||||
|
subreddit(&sub).await.unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
Subreddit::default()
|
||||||
|
}
|
||||||
|
} else if sub.contains('+') {
|
||||||
|
// Multireddit
|
||||||
Subreddit {
|
Subreddit {
|
||||||
name: sub_name,
|
name: sub,
|
||||||
..Subreddit::default()
|
..Subreddit::default()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -63,6 +84,50 @@ pub async fn page(req: HttpRequest) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sub or unsub by setting subscription cookie using response "Set-Cookie" header
|
||||||
|
pub async fn subscriptions(req: HttpRequest) -> HttpResponse {
|
||||||
|
let mut res = HttpResponse::Found();
|
||||||
|
|
||||||
|
let sub = req.match_info().get("sub").unwrap_or_default().to_string();
|
||||||
|
let action = req.match_info().get("action").unwrap_or_default().to_string();
|
||||||
|
let mut sub_list = prefs(req.to_owned()).subs;
|
||||||
|
|
||||||
|
// Modify sub list based on action
|
||||||
|
if action == "subscribe" && !sub_list.contains(&sub) {
|
||||||
|
sub_list.push(sub.to_owned());
|
||||||
|
sub_list.sort();
|
||||||
|
} else if action == "unsubscribe" {
|
||||||
|
sub_list.retain(|s| s != &sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete cookie if empty, else set
|
||||||
|
if sub_list.is_empty() {
|
||||||
|
res.del_cookie(&Cookie::build("subscriptions", "").path("/").finish());
|
||||||
|
} else {
|
||||||
|
res.cookie(
|
||||||
|
Cookie::build("subscriptions", sub_list.join("+"))
|
||||||
|
.path("/")
|
||||||
|
.http_only(true)
|
||||||
|
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
|
||||||
|
.finish(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect back to subreddit
|
||||||
|
// check for redirect parameter if unsubscribing from outside sidebar
|
||||||
|
let redirect_path = param(&req.uri().to_string(), "redirect");
|
||||||
|
let path = if !redirect_path.is_empty() && redirect_path.starts_with('/') {
|
||||||
|
redirect_path
|
||||||
|
} else {
|
||||||
|
format!("/r/{}", sub)
|
||||||
|
};
|
||||||
|
|
||||||
|
res
|
||||||
|
.content_type("text/html")
|
||||||
|
.set_header("Location", path.to_owned())
|
||||||
|
.body(format!("Redirecting to <a href=\"{0}\">{0}</a>...", path))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn wiki(req: HttpRequest) -> HttpResponse {
|
pub async fn wiki(req: HttpRequest) -> HttpResponse {
|
||||||
let sub = req.match_info().get("sub").unwrap_or("reddit.com").to_string();
|
let sub = req.match_info().get("sub").unwrap_or("reddit.com").to_string();
|
||||||
let page = req.match_info().get("page").unwrap_or("index").to_string();
|
let page = req.match_info().get("page").unwrap_or("index").to_string();
|
||||||
|
29
src/utils.rs
29
src/utils.rs
@ -9,7 +9,7 @@ use serde_json::{from_str, Value};
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use time::{Duration, OffsetDateTime};
|
use time::{Duration, OffsetDateTime};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use cached::proc_macro::cached;
|
// use cached::proc_macro::cached;
|
||||||
|
|
||||||
//
|
//
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
@ -127,8 +127,9 @@ pub struct Preferences {
|
|||||||
pub front_page: String,
|
pub front_page: String,
|
||||||
pub layout: String,
|
pub layout: String,
|
||||||
pub wide: String,
|
pub wide: String,
|
||||||
pub hide_nsfw: String,
|
pub show_nsfw: String,
|
||||||
pub comment_sort: String,
|
pub comment_sort: String,
|
||||||
|
pub subs: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -142,8 +143,9 @@ pub fn prefs(req: HttpRequest) -> Preferences {
|
|||||||
front_page: cookie(&req, "front_page"),
|
front_page: cookie(&req, "front_page"),
|
||||||
layout: cookie(&req, "layout"),
|
layout: cookie(&req, "layout"),
|
||||||
wide: cookie(&req, "wide"),
|
wide: cookie(&req, "wide"),
|
||||||
hide_nsfw: cookie(&req, "hide_nsfw"),
|
show_nsfw: cookie(&req, "show_nsfw"),
|
||||||
comment_sort: cookie(&req, "comment_sort"),
|
comment_sort: cookie(&req, "comment_sort"),
|
||||||
|
subs: cookie(&req, "subscriptions").split('+').map(String::from).filter(|s| !s.is_empty()).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,7 +343,11 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec<Post
|
|||||||
},
|
},
|
||||||
distinguished: val(post, "distinguished"),
|
distinguished: val(post, "distinguished"),
|
||||||
},
|
},
|
||||||
score: format_num(score),
|
score: if post["data"]["hide_score"].as_bool().unwrap_or_default() {
|
||||||
|
"•".to_string()
|
||||||
|
} else {
|
||||||
|
format_num(score)
|
||||||
|
},
|
||||||
upvote_ratio: ratio as i64,
|
upvote_ratio: ratio as i64,
|
||||||
post_type,
|
post_type,
|
||||||
thumbnail: Media {
|
thumbnail: Media {
|
||||||
@ -393,7 +399,7 @@ pub async fn error(msg: String) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make a request to a Reddit API and parse the JSON response
|
// Make a request to a Reddit API and parse the JSON response
|
||||||
#[cached(size=1000,time=60, result = true)]
|
// #[cached(size=100,time=60, result = true)]
|
||||||
pub async fn request(path: String) -> Result<Value, String> {
|
pub async fn request(path: String) -> Result<Value, String> {
|
||||||
let url = format!("https://www.reddit.com{}", path);
|
let url = format!("https://www.reddit.com{}", path);
|
||||||
let user_agent = format!("web:libreddit:{}", env!("CARGO_PKG_VERSION"));
|
let user_agent = format!("web:libreddit:{}", env!("CARGO_PKG_VERSION"));
|
||||||
@ -459,11 +465,11 @@ pub async fn request(path: String) -> Result<Value, String> {
|
|||||||
// If response is success
|
// If response is success
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
// Parse the response from Reddit as JSON
|
// Parse the response from Reddit as JSON
|
||||||
match from_str(&response.into_string().unwrap()) {
|
let json_string = &response.into_string().unwrap_or_default();
|
||||||
|
match from_str(json_string) {
|
||||||
Ok(json) => Ok(json),
|
Ok(json) => Ok(json),
|
||||||
Err(_) => {
|
Err(e) => {
|
||||||
#[cfg(debug_assertions)]
|
println!("{} - Failed to parse page JSON data: {} - {}", url, e, json_string);
|
||||||
dbg!(format!("{} - Failed to parse page JSON data", url));
|
|
||||||
Err("Failed to parse page JSON data".to_string())
|
Err("Failed to parse page JSON data".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -475,9 +481,8 @@ pub async fn request(path: String) -> Result<Value, String> {
|
|||||||
Err("Page not found".to_string())
|
Err("Page not found".to_string())
|
||||||
}
|
}
|
||||||
// If failed to send request
|
// If failed to send request
|
||||||
Err(_e) => {
|
Err(e) => {
|
||||||
#[cfg(debug_assertions)]
|
println!("{} - Couldn't send request to Reddit: {}", url, e);
|
||||||
dbg!(format!("{} - {}", url, _e));
|
|
||||||
Err("Couldn't send request to Reddit, this instance may be being rate-limited. Try another.".to_string())
|
Err("Couldn't send request to Reddit, this instance may be being rate-limited. Try another.".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
static/logo.png
Normal file
BIN
static/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
15
static/manifest.json
Normal file
15
static/manifest.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "Libreddit",
|
||||||
|
"short_name": "Libreddit",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#2A3443",
|
||||||
|
"description": "An alternative private front-end to Reddit",
|
||||||
|
"theme_color": "#2A3443",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "./logo.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
179
static/style.css
179
static/style.css
@ -58,6 +58,11 @@
|
|||||||
background: var(--accent);
|
background: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
outline: 2px solid var(--accent);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
html, body, div, h1, h2, h3, h4, h5, h6, ul, ol, dl, li, dt, dd, p, blockquote,
|
html, body, div, h1, h2, h3, h4, h5, h6, ul, ol, dl, li, dt, dd, p, blockquote,
|
||||||
pre, form, fieldset, table, th, td, select, input {
|
pre, form, fieldset, table, th, td, select, input {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -68,11 +73,12 @@ pre, form, fieldset, table, th, td, select, input {
|
|||||||
body {
|
body {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
padding-top: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-areas: "logo searchbox code";
|
grid-template-areas: "logo searchbox links";
|
||||||
|
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -83,7 +89,7 @@ nav {
|
|||||||
|
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
|
||||||
z-index: 1;
|
z-index: 2;
|
||||||
top: 0;
|
top: 0;
|
||||||
padding: 5px 15px;
|
padding: 5px 15px;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
@ -92,23 +98,49 @@ nav {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nav * { color: var(--text); }
|
nav * { color: var(--text); }
|
||||||
nav #reddit, #code { color: var(--accent); }
|
nav #reddit, #code > span { color: var(--accent); }
|
||||||
nav #logo { grid-area: logo; }
|
nav #code > svg { stroke: var(--accent); }
|
||||||
nav #code { grid-area: code; }
|
|
||||||
nav #version { opacity: 50%; }
|
nav #logo {
|
||||||
|
grid-area: logo;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav #links {
|
||||||
|
grid-area: links;
|
||||||
|
margin-left: 10px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav #links svg {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav #version {
|
||||||
|
opacity: 50%;
|
||||||
|
vertical-align: -2px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav #libreddit {
|
||||||
|
vertical-align: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
#settings_link {
|
#settings_link {
|
||||||
font-size: 18px;
|
|
||||||
margin-left: 20px;
|
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#code {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
margin: 60px auto 20px auto
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wide main {
|
.wide main {
|
||||||
@ -232,6 +264,71 @@ aside {
|
|||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subscriptions */
|
||||||
|
|
||||||
|
#sub_subscription {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe, .unsubscribe {
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe {
|
||||||
|
color: var(--foreground);
|
||||||
|
background-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.unsubscribe {
|
||||||
|
color: var(--text);
|
||||||
|
background-color: var(--highlighted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subscribed subreddit list */
|
||||||
|
|
||||||
|
#subscriptions {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: var(--panel-border);
|
||||||
|
background-color: var(--outside);
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 15px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#subscriptions > summary {
|
||||||
|
padding: 8px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sub_list {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
min-width: 100%;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
background: var(--outside);
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: auto;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sub_list > a {
|
||||||
|
padding: 10px 20px;
|
||||||
|
transition: 0.2s background;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sub_list > .selected {
|
||||||
|
background-color: var(--accent);
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sub_list > a:not(.selected):hover {
|
||||||
|
background-color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
/* Wiki Pages */
|
/* Wiki Pages */
|
||||||
|
|
||||||
#wiki {
|
#wiki {
|
||||||
@ -304,6 +401,7 @@ select, #search {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
border-right: 2px var(--outside) solid;
|
border-right: 2px var(--outside) solid;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
max-width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#restrict_sr { margin-right: 5px; }
|
#restrict_sr { margin-right: 5px; }
|
||||||
@ -451,10 +549,6 @@ a.search_subreddit:hover {
|
|||||||
|
|
||||||
.post:not(:last-child) { margin-bottom: 10px; }
|
.post:not(:last-child) { margin-bottom: 10px; }
|
||||||
|
|
||||||
.post.highlighted {
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post:hover {
|
.post:hover {
|
||||||
background: var(--foreground);
|
background: var(--foreground);
|
||||||
}
|
}
|
||||||
@ -788,7 +882,7 @@ a.search_subreddit:hover {
|
|||||||
|
|
||||||
/* Settings */
|
/* Settings */
|
||||||
|
|
||||||
#settings {
|
#settings, #settings > form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -801,7 +895,7 @@ a.search_subreddit:hover {
|
|||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
#prefs {
|
.prefs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -811,7 +905,7 @@ a.search_subreddit:hover {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#prefs > div {
|
.prefs > div {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -819,17 +913,21 @@ a.search_subreddit:hover {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#prefs > div:not(:last-of-type) {
|
.prefs > div:not(:last-of-type) {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#prefs select {
|
.prefs select {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
background: var(--foreground);
|
background: var(--foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aside.prefs {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
#save {
|
#save {
|
||||||
background: var(--highlighted);
|
background: var(--highlighted);
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
@ -842,6 +940,27 @@ input[type="submit"] {
|
|||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#settings_subs {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#settings_subs > li {
|
||||||
|
display: flex;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
#settings_subs > li:last-of-type { margin-bottom: 0; }
|
||||||
|
|
||||||
|
#settings_subs > li > span {
|
||||||
|
padding: 10px 0;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#settings_subs .unsubscribe {
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Markdown */
|
/* Markdown */
|
||||||
|
|
||||||
.md > *:not(:first-child) {
|
.md > *:not(:first-child) {
|
||||||
@ -915,6 +1034,8 @@ td, th {
|
|||||||
/* Mobile */
|
/* Mobile */
|
||||||
|
|
||||||
@media screen and (max-width: 480px) {
|
@media screen and (max-width: 480px) {
|
||||||
|
#version { display: none; }
|
||||||
|
|
||||||
.post {
|
.post {
|
||||||
grid-template: "post_header post_header post_thumbnail" auto
|
grid-template: "post_header post_header post_thumbnail" auto
|
||||||
"post_title post_title post_thumbnail" 1fr
|
"post_title post_title post_thumbnail" 1fr
|
||||||
@ -953,25 +1074,39 @@ td, th {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 800px) {
|
@media screen and (max-width: 800px) {
|
||||||
|
body { padding-top: 120px }
|
||||||
|
|
||||||
main {
|
main {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: 100px 0 10px 0;
|
margin: 0 0 10px 0;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
grid-template-areas: 'logo code' 'searchbox searchbox';
|
grid-template-areas: 'logo links' 'searchbox searchbox';
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: calc(100% - 20px);
|
width: calc(100% - 20px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nav #links { margin-left: auto; }
|
||||||
|
nav #links span { display: none; }
|
||||||
|
nav #links svg { display: block; }
|
||||||
|
|
||||||
|
#subscriptions { position: unset; }
|
||||||
|
|
||||||
|
#sub_list {
|
||||||
|
left: 10px;
|
||||||
|
right: 10px;
|
||||||
|
min-width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
aside, #subreddit, #user {
|
aside, #subreddit, #user {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#user, #sidebar { margin: 20px 0; }
|
#user, #sidebar { margin: 20px 0; }
|
||||||
#logo { margin: 5px auto; }
|
#logo, #links { margin-bottom: 5px; }
|
||||||
#searchbox { width: 100%; }
|
#searchbox { width: calc(100vw - 35px); }
|
||||||
}
|
}
|
||||||
|
BIN
static/touch-icon-iphone.png
Normal file
BIN
static/touch-icon-iphone.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
@ -3,13 +3,24 @@
|
|||||||
<head>
|
<head>
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<title>{% block title %}Libreddit{% endblock %}</title>
|
<title>{% block title %}Libreddit{% endblock %}</title>
|
||||||
<meta http-equiv="Referrer-Policy" content="no-referrer">
|
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self';">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
<meta name="description" content="View on Libreddit, an alternative private front-end to Reddit.">
|
<meta name="description" content="View on Libreddit, an alternative private front-end to Reddit.">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<!-- General PWA -->
|
||||||
|
<meta name="theme-color" content="#009a9a"/>
|
||||||
|
<!-- iOS Application -->
|
||||||
|
<meta name="apple-mobile-web-app-title" content="Libreddit">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||||
|
<!-- Android -->
|
||||||
|
<meta name="theme-color" content="#2A3443">
|
||||||
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
|
<!-- iOS Logo -->
|
||||||
|
<link href="/touch-icon-iphone.png" rel="apple-touch-icon">
|
||||||
|
<!-- PWA Manifest -->
|
||||||
|
<link rel="manifest" type="application/json" href="/manifest.json">
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
|
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
|
||||||
<link rel="stylesheet" href="/style.css">
|
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body class="
|
<body class="
|
||||||
@ -18,15 +29,22 @@
|
|||||||
{% if prefs.theme != "system" %} {{ prefs.theme }}{% endif %}">
|
{% if prefs.theme != "system" %} {{ prefs.theme }}{% endif %}">
|
||||||
<!-- NAVIGATION BAR -->
|
<!-- NAVIGATION BAR -->
|
||||||
<nav>
|
<nav>
|
||||||
<p id="logo">
|
<div id="logo">
|
||||||
<a id="libreddit" href="/">
|
<a id="libreddit" href="/"><span id="lib">lib</span><span id="reddit">reddit.</span></a>
|
||||||
<span id="lib">lib</span><span id="reddit">reddit.</span>
|
|
||||||
</a>
|
|
||||||
<span id="version">v{{ env!("CARGO_PKG_VERSION") }}</span>
|
<span id="version">v{{ env!("CARGO_PKG_VERSION") }}</span>
|
||||||
<a id="settings_link" href="/settings">settings</a>
|
{% block subscriptions %}{% endblock %}
|
||||||
</p>
|
</div>
|
||||||
{% block search %}{% endblock %}
|
{% block search %}{% endblock %}
|
||||||
<a id="code" href="https://github.com/spikecodes/libreddit">code</a>
|
<div id="links">
|
||||||
|
<a id="settings_link" href="/settings">
|
||||||
|
<span>settings</span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||||
|
</a>
|
||||||
|
<a id="code" href="https://github.com/spikecodes/libreddit">
|
||||||
|
<span>code</span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- MAIN CONTENT -->
|
<!-- MAIN CONTENT -->
|
||||||
|
@ -13,6 +13,10 @@
|
|||||||
<meta name="author" content="u/{{ post.author.name }}">
|
<meta name="author" content="u/{{ post.author.name }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block subscriptions %}
|
||||||
|
{% call utils::sub_list(post.community.as_str()) %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<!-- OPEN COMMENT MACRO -->
|
<!-- OPEN COMMENT MACRO -->
|
||||||
{% macro comment(item) -%}
|
{% macro comment(item) -%}
|
||||||
<div id="{{ item.id }}" class="comment">
|
<div id="{{ item.id }}" class="comment">
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
{% block title %}Libreddit: search results - {{ params.q }}{% endblock %}
|
{% block title %}Libreddit: search results - {{ params.q }}{% endblock %}
|
||||||
|
|
||||||
|
{% block subscriptions %}
|
||||||
|
{% call utils::sub_list("") %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="column_one">
|
<div id="column_one">
|
||||||
<form id="search_sort">
|
<form id="search_sort">
|
||||||
@ -42,7 +46,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% for post in posts %}
|
{% for post in posts %}
|
||||||
|
|
||||||
{% if post.flags.nsfw && prefs.hide_nsfw == "on" %}
|
{% if post.flags.nsfw && prefs.show_nsfw != "on" %}
|
||||||
{% else if post.title != "Comment" %}
|
{% else if post.title != "Comment" %}
|
||||||
<div class="post {% if post.flags.stickied %}stickied{% endif %}">
|
<div class="post {% if post.flags.stickied %}stickied{% endif %}">
|
||||||
<p class="post_header">
|
<p class="post_header">
|
||||||
|
@ -8,8 +8,9 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<form id="settings" action="/settings" method="POST">
|
<div id="settings">
|
||||||
<div id="prefs">
|
<form action="/settings" method="POST">
|
||||||
|
<div class="prefs">
|
||||||
<p>Appearance</p>
|
<p>Appearance</p>
|
||||||
<div id="theme">
|
<div id="theme">
|
||||||
<label for="theme">Theme:</label>
|
<label for="theme">Theme:</label>
|
||||||
@ -21,7 +22,7 @@
|
|||||||
<div id="front_page">
|
<div id="front_page">
|
||||||
<label for="front_page">Front page:</label>
|
<label for="front_page">Front page:</label>
|
||||||
<select name="front_page">
|
<select name="front_page">
|
||||||
{% call utils::options(prefs.front_page, ["popular", "all"], "popular") %}
|
{% call utils::options(prefs.front_page, ["default", "popular", "all"], "default") %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div id="layout">
|
<div id="layout">
|
||||||
@ -41,12 +42,29 @@
|
|||||||
{% call utils::options(prefs.comment_sort, ["confidence", "top", "new", "controversial", "old"], "confidence") %}
|
{% call utils::options(prefs.comment_sort, ["confidence", "top", "new", "controversial", "old"], "confidence") %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div id="hide_nsfw">
|
<div id="show_nsfw">
|
||||||
<label for="hide_nsfw">Hide NSFW posts:</label>
|
<label for="show_nsfw">Show NSFW posts:</label>
|
||||||
<input type="checkbox" name="hide_nsfw" {% if prefs.hide_nsfw == "on" %}checked{% endif %}>
|
<input type="checkbox" name="show_nsfw" {% if prefs.show_nsfw == "on" %}checked{% endif %}>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p id="settings_note"><b>Note:</b> settings are saved in browser cookies. Clearing your cookie data will reset them.</p>
|
<p id="settings_note"><b>Note:</b> settings are saved in browser cookies. Clearing your cookie data will reset them.</p>
|
||||||
<input id="save" type="submit" value="Save">
|
<input id="save" type="submit" value="Save">
|
||||||
</form>
|
</form>
|
||||||
|
{% if prefs.subs.len() > 0 %}
|
||||||
|
<aside class="prefs">
|
||||||
|
<p>Subscribed Subreddits</p>
|
||||||
|
<ul id="settings_subs">
|
||||||
|
{% for sub in prefs.subs %}
|
||||||
|
<li>
|
||||||
|
<span>{{ sub }}</span>
|
||||||
|
<form action="/r/{{ sub }}/unsubscribe/?redirect=/settings" method="POST">
|
||||||
|
<button class="unsubscribe">Unsubscribe</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</aside>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
{% call utils::search(["/r/", sub.name.as_str()].concat(), "") %}
|
{% call utils::search(["/r/", sub.name.as_str()].concat(), "") %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block subscriptions %}
|
||||||
|
{% call utils::sub_list(sub.name.as_str(), "wide") %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<main>
|
<main>
|
||||||
<div id="column_one">
|
<div id="column_one">
|
||||||
@ -37,7 +41,7 @@
|
|||||||
|
|
||||||
<div id="posts">
|
<div id="posts">
|
||||||
{% for post in posts %}
|
{% for post in posts %}
|
||||||
{% if !(post.flags.nsfw && prefs.hide_nsfw == "on") %}
|
{% if !(post.flags.nsfw && prefs.show_nsfw != "on") %}
|
||||||
<hr class="sep" />
|
<hr class="sep" />
|
||||||
<div class="post {% if post.flags.stickied %}stickied{% endif %}">
|
<div class="post {% if post.flags.stickied %}stickied{% endif %}">
|
||||||
<p class="post_header">
|
<p class="post_header">
|
||||||
@ -121,6 +125,17 @@
|
|||||||
<div>{{ sub.members }}</div>
|
<div>{{ sub.members }}</div>
|
||||||
<div>{{ sub.active }}</div>
|
<div>{{ sub.active }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="sub_subscription">
|
||||||
|
{% if prefs.subs.contains(sub.name) %}
|
||||||
|
<form action="/r/{{ sub.name }}/unsubscribe" method="POST">
|
||||||
|
<button class="unsubscribe">Unsubscribe</button>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<form action="/r/{{ sub.name }}/subscribe" method="POST">
|
||||||
|
<button class="subscribe">Subscribe</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<details class="panel" id="sidebar">
|
<details class="panel" id="sidebar">
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
|
|
||||||
{% block title %}{{ user.name.replace("u/", "") }} (u/{{ user.name }}) - Libreddit{% endblock %}
|
{% block title %}{{ user.name.replace("u/", "") }} (u/{{ user.name }}) - Libreddit{% endblock %}
|
||||||
|
|
||||||
|
{% block subscriptions %}
|
||||||
|
{% call utils::sub_list("") %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<main>
|
<main>
|
||||||
<div id="column_one">
|
<div id="column_one">
|
||||||
@ -27,7 +31,7 @@
|
|||||||
<div id="posts">
|
<div id="posts">
|
||||||
{% for post in posts %}
|
{% for post in posts %}
|
||||||
|
|
||||||
{% if post.flags.nsfw && prefs.hide_nsfw == "on" %}
|
{% if post.flags.nsfw && prefs.show_nsfw != "on" %}
|
||||||
{% else if post.title != "Comment" %}
|
{% else if post.title != "Comment" %}
|
||||||
<div class="post {% if post.flags.stickied %}stickied{% endif %}">
|
<div class="post {% if post.flags.stickied %}stickied{% endif %}">
|
||||||
<p class="post_header">
|
<p class="post_header">
|
||||||
|
@ -39,3 +39,16 @@
|
|||||||
{% else if flair_part.flair_part_type == "text" %}<span>{{ flair_part.value }}</span>{% endif %}
|
{% else if flair_part.flair_part_type == "text" %}<span>{{ flair_part.value }}</span>{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro sub_list(current) -%}
|
||||||
|
{% if prefs.subs.len() > 0 %}
|
||||||
|
<details id="subscriptions">
|
||||||
|
<summary>Subscriptions</summary>
|
||||||
|
<div id="sub_list">
|
||||||
|
{% for sub in prefs.subs %}
|
||||||
|
<a href="/r/{{ sub }}" {% if sub == current %}class="selected"{% endif %}>{{ sub }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
{% call utils::search(["/r/", sub.as_str()].concat(), "") %}
|
{% call utils::search(["/r/", sub.as_str()].concat(), "") %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block subscriptions %}
|
||||||
|
{% call utils::sub_list(sub.as_str()) %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<main>
|
<main>
|
||||||
<div class="panel" id="column_one">
|
<div class="panel" id="column_one">
|
||||||
|
Loading…
Reference in New Issue
Block a user