diff options
author | Soispha <soispha@vhack.eu> | 2024-01-28 18:20:47 +0100 |
---|---|---|
committer | Soispha <soispha@vhack.eu> | 2024-01-28 18:20:47 +0100 |
commit | 736d4483985376aac995a5526c6a7f47edea0d2b (patch) | |
tree | 4cded31bf238042cd0e1777ef9afd50641857136 /sys | |
parent | build(treewide): Update (diff) | |
download | nixos-config-736d4483985376aac995a5526c6a7f47edea0d2b.tar.gz nixos-config-736d4483985376aac995a5526c6a7f47edea0d2b.zip |
feat(sys/nixpkgs/pkgs/comments): Init
This rewrite of the `comments` script even provides nested comments
Diffstat (limited to 'sys')
-rwxr-xr-x | sys/nixpkgs/pkgs/comments/.env | 3 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/.envrc | 1 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/.gitignore | 3 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/Cargo.lock | 442 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/Cargo.toml | 16 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/comments.nix | 25 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/default.nix | 18 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/flake.lock | 61 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/flake.nix | 31 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/src/info_json.rs | 218 | ||||
-rw-r--r-- | sys/nixpkgs/pkgs/comments/src/main.rs | 322 | ||||
-rwxr-xr-x | sys/nixpkgs/pkgs/comments/update.sh | 6 |
12 files changed, 1146 insertions, 0 deletions
diff --git a/sys/nixpkgs/pkgs/comments/.env b/sys/nixpkgs/pkgs/comments/.env new file mode 100755 index 00000000..8018a738 --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/.env @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +PATH="$(pwd)/target/release/:$(pwd)/target/debug/:$PATH" diff --git a/sys/nixpkgs/pkgs/comments/.envrc b/sys/nixpkgs/pkgs/comments/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/.envrc @@ -0,0 +1 @@ +use flake diff --git a/sys/nixpkgs/pkgs/comments/.gitignore b/sys/nixpkgs/pkgs/comments/.gitignore new file mode 100644 index 00000000..c84fa049 --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/.gitignore @@ -0,0 +1,3 @@ +# build dirs +/target +/result diff --git a/sys/nixpkgs/pkgs/comments/Cargo.lock b/sys/nixpkgs/pkgs/comments/Cargo.lock new file mode 100644 index 00000000..f2569a2f --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/Cargo.lock @@ -0,0 +1,442 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "chrono-humanize" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b" +dependencies = [ + "chrono", +] + +[[package]] +name = "cli-log" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d2ab00dc4c82ec28af25ac085aecc11ffeabf353755715a3113a7aa044ca5cc" +dependencies = [ + "chrono", + "file-size", + "log", + "proc-status", +] + +[[package]] +name = "comments" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "chrono-humanize", + "cli-log", + "log", + "regex", + "serde", + "serde_json", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "file-size" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9544f10105d33957765016b8a9baea7e689bf1f0f2f32c2fa2f568770c38d2b3" + +[[package]] +name = "iana-time-zone" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "js-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-status" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e0c0ac915e7b76b47850ba4ffc377abde6c6ff9eeace61d0a89623db449712" +dependencies = [ + "thiserror", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d1bd37ce2324cf3bf85e5a25f96eb4baf0d5aa6eba43e7ae8958870c4ec48ed" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/sys/nixpkgs/pkgs/comments/Cargo.toml b/sys/nixpkgs/pkgs/comments/Cargo.toml new file mode 100644 index 00000000..28a5ea50 --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "comments" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.79" +chrono = "0.4.33" +chrono-humanize = "0.2.3" +cli-log = "2.0.0" +log = "0.4.20" +regex = "1.10.3" +serde = { version = "1.0.195", features = ["derive"] } +serde_json = "1.0.111" diff --git a/sys/nixpkgs/pkgs/comments/comments.nix b/sys/nixpkgs/pkgs/comments/comments.nix new file mode 100644 index 00000000..a46f1ebe --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/comments.nix @@ -0,0 +1,25 @@ +{ + lib, + rustPlatform, + makeWrapper, + less, + fmt, +}: +rustPlatform.buildRustPackage { + pname = "comments"; + version = "0.1.0"; + + src = ./.; + cargoLock = { + lockFile = ./Cargo.lock; + }; + + nativeBuildInputs = [ + makeWrapper + ]; + + postInstall = '' + wrapProgram $out/bin/comments \ + --set PATH ${lib.makeBinPath [less fmt]} + ''; +} diff --git a/sys/nixpkgs/pkgs/comments/default.nix b/sys/nixpkgs/pkgs/comments/default.nix new file mode 100644 index 00000000..c1f5459c --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/default.nix @@ -0,0 +1,18 @@ +[ + ( + final: prev: { + yt = import ./comments.nix { + inherit + (prev) + lib + makeWrapper + rustPlatform + # dependencies + + less + fmt + ; + }; + } + ) +] diff --git a/sys/nixpkgs/pkgs/comments/flake.lock b/sys/nixpkgs/pkgs/comments/flake.lock new file mode 100644 index 00000000..8e5a9529 --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1705856552, + "narHash": "sha256-JXfnuEf5Yd6bhMs/uvM67/joxYKoysyE3M2k6T3eWbg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "612f97239e2cc474c13c9dafa0df378058c5ad8d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/sys/nixpkgs/pkgs/comments/flake.nix b/sys/nixpkgs/pkgs/comments/flake.nix new file mode 100644 index 00000000..f5e44a65 --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/flake.nix @@ -0,0 +1,31 @@ +{ + description = "comments"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { + self, + nixpkgs, + flake-utils, + }: (flake-utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacyPackages."${system}"; + in { + devShells.default = pkgs.mkShell { + packages = with pkgs; [ + # rust stuff + cargo + clippy + rustc + rustfmt + + cargo-edit + cargo-expand + cargo-audit + ]; + }; + })); +} diff --git a/sys/nixpkgs/pkgs/comments/src/info_json.rs b/sys/nixpkgs/pkgs/comments/src/info_json.rs new file mode 100644 index 00000000..48a35777 --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/src/info_json.rs @@ -0,0 +1,218 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Deserializer}; + +#[derive(Debug, Deserialize)] +pub struct InfoJson { + pub id: String, + pub title: String, + pub formats: Vec<Format>, + pub thumbnails: Vec<ThumbNail>, + pub thumbnail: String, + pub description: String, + pub channel_id: String, + pub channel_url: String, + pub duration: u32, + pub view_count: u32, + pub age_limit: u32, + pub webpage_url: String, + pub categories: Vec<String>, + pub tags: Vec<String>, + pub playable_in_embed: bool, + pub live_status: String, + _format_sort_fields: Vec<String>, + pub automatic_captions: HashMap<String, Vec<Caption>>, + pub subtitles: Subtitles, + pub comment_count: u32, + pub like_count: u32, + pub channel: String, + pub channel_follower_count: u32, + pub channel_is_verified: bool, + pub uploader: String, + pub uploader_id: String, + pub uploader_url: String, + pub upload_date: String, + pub availability: String, + pub webpage_url_basename: String, + pub webpage_url_domain: String, + pub extractor: String, + pub extractor_key: String, + pub display_id: String, + pub fulltitle: String, + pub duration_string: String, + pub is_live: bool, + pub was_live: bool, + pub epoch: u32, + pub comments: Vec<Comment>, + pub sponsorblock_chapters: Vec<SponsorblockChapter>, + pub format: String, + pub format_id: String, + pub ext: String, + pub protocol: String, + pub language: Option<String>, + pub format_note: String, + pub filesize_approx: u32, + pub tbr: f64, + pub width: u32, + pub height: u32, + pub resolution: String, + pub fps: f64, + pub dynamic_range: String, + pub vcodec: String, + pub vbr: f64, + pub aspect_ratio: f64, + pub acodec: String, + pub abr: f64, + pub asr: u32, + pub audio_channels: u32, + _type: String, + _version: Version, +} + +#[derive(Debug, Deserialize)] +pub struct Subtitles {} + +#[derive(Debug, Deserialize)] +pub struct Version { + pub version: String, + pub release_git_head: String, + pub repository: String, +} + +#[derive(Debug, Deserialize)] +pub struct SponsorblockChapter {} + +#[derive(Debug, Deserialize, Clone)] +#[serde(from = "String")] +pub enum Parent { + Root, + Id(String), +} + +impl Parent { + pub fn id(&self) -> Option<&str> { + if let Self::Id(id) = self { + Some(&id) + } else { + None + } + } +} + +impl From<String> for Parent { + fn from(value: String) -> Self { + if value == "root" { + Self::Root + } else { + Self::Id(value) + } + } +} + +#[derive(Debug, Deserialize, Clone)] +#[serde(from = "String")] +pub struct Id { + pub id: String, +} +impl From<String> for Id { + fn from(value: String) -> Self { + Self { + // Take the last element if the string is split with dots, otherwise take the full id + id: value.split('.').last().unwrap_or(&value).to_owned(), + } + } +} + +#[derive(Debug, Deserialize, Clone)] +pub struct Comment { + pub id: Id, + pub text: String, + #[serde(default = "zero")] + pub like_count: u32, + pub author_id: String, + pub author: String, + pub author_thumbnail: String, + pub parent: Parent, + #[serde(deserialize_with = "edited_from_time_text", alias = "_time_text")] + pub edited: bool, + // Can't also be deserialized, as it's already used in 'edited' + // _time_text: String, + pub timestamp: i64, + pub author_url: String, + pub author_is_uploader: bool, + pub is_favorited: bool, +} +fn zero() -> u32 { + 0 +} +fn edited_from_time_text<'de, D>(d: D) -> Result<bool, D::Error> +where + D: Deserializer<'de>, +{ + let s = String::deserialize(d)?; + if s.contains(" (edited)") { + Ok(true) + } else { + Ok(false) + } +} + +#[derive(Debug, Deserialize)] +pub struct Caption { + pub ext: String, + pub url: String, + pub name: String, +} + +#[derive(Debug, Deserialize)] +pub struct ThumbNail { + pub url: String, + pub preference: i32, + pub id: String, + pub height: Option<u32>, + pub width: Option<u32>, + pub resolution: Option<String>, +} + +#[derive(Debug, Deserialize)] +pub struct Format { + pub format_id: String, + pub format_note: Option<String>, + pub ext: String, + pub protocol: String, + pub acodec: Option<String>, + pub vcodec: String, + pub url: String, + pub width: Option<u32>, + pub height: Option<u32>, + pub fps: Option<f64>, + pub rows: Option<u32>, + pub columns: Option<u32>, + pub fragments: Option<Vec<Fragment>>, + pub resolution: String, + pub aspect_ratio: Option<f64>, + pub http_headers: HttpHeader, + pub audio_ext: String, + pub video_ext: String, + pub vbr: Option<f64>, + pub abr: Option<f64>, + pub format: String, +} + +#[derive(Debug, Deserialize)] +pub struct HttpHeader { + #[serde(alias = "User-Agent")] + pub user_agent: String, + #[serde(alias = "Accept")] + pub accept: String, + #[serde(alias = "Accept-Language")] + pub accept_language: String, + #[serde(alias = "Sec-Fetch-Mode")] + pub sec_fetch_mode: String, +} + +#[derive(Debug, Deserialize)] +pub struct Fragment { + pub url: String, + pub duration: f64, +} diff --git a/sys/nixpkgs/pkgs/comments/src/main.rs b/sys/nixpkgs/pkgs/comments/src/main.rs new file mode 100644 index 00000000..de98d75e --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/src/main.rs @@ -0,0 +1,322 @@ +use std::{ + env, + fmt::Display, + fs::{self, File}, + io::{BufReader, Write}, + mem, + path::PathBuf, + process::{Command, Stdio}, +}; + +use anyhow::Context; +use chrono::{Local, TimeZone}; +use chrono_humanize::{Accuracy, HumanTime, Tense}; +use info_json::{Comment, InfoJson, Parent}; +use regex::Regex; + +mod info_json; + +fn get_runtime_path(component: &'static str) -> anyhow::Result<PathBuf> { + let out: PathBuf = format!( + "{}/{}", + env::var("XDG_RUNTIME_DIR").expect("This should always exist"), + component + ) + .into(); + fs::create_dir_all(out.parent().expect("Parent should exist"))?; + Ok(out) +} + +const STATUS_PATH: &str = "ytcc/running"; +pub fn status_path() -> anyhow::Result<PathBuf> { + get_runtime_path(STATUS_PATH) +} + +#[derive(Debug, Clone)] +pub struct CommentExt { + pub value: Comment, + pub replies: Vec<CommentExt>, +} + +#[derive(Debug, Default)] +pub struct Comments { + vec: Vec<CommentExt>, +} + +impl Comments { + pub fn new() -> Self { + Self::default() + } + pub fn push(&mut self, value: CommentExt) { + self.vec.push(value); + } + pub fn get_mut(&mut self, key: &str) -> Option<&mut CommentExt> { + self.vec.iter_mut().filter(|c| c.value.id.id == key).last() + } + pub fn insert(&mut self, key: &str, value: CommentExt) { + let parent = self + .vec + .iter_mut() + .filter(|c| c.value.id.id == key) + .last() + .expect("One of these should exist"); + parent.push_reply(value); + } +} +impl CommentExt { + pub fn push_reply(&mut self, value: CommentExt) { + self.replies.push(value) + } + pub fn get_mut_reply(&mut self, key: &str) -> Option<&mut CommentExt> { + self.replies + .iter_mut() + .filter(|c| c.value.id.id == key) + .last() + } +} + +impl From<Comment> for CommentExt { + fn from(value: Comment) -> Self { + Self { + replies: vec![], + value, + } + } +} + +impl Display for Comments { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + macro_rules! c { + ($color:expr, $write:ident) => { + $write.write_str(concat!("\x1b[", $color, "m"))? + }; + } + + fn format( + comment: &CommentExt, + f: &mut std::fmt::Formatter<'_>, + ident_count: u32, + ) -> std::fmt::Result { + let ident = &(0..ident_count).map(|_| " ").collect::<String>(); + let value = &comment.value; + + f.write_str(&ident)?; + + if value.author_is_uploader { + c!("91;1", f); + } else { + c!("35", f); + } + + f.write_str(&value.author)?; + c!("0", f); + if value.edited || value.is_favorited { + f.write_str("[")?; + if value.edited { + f.write_str("")?; + } + if value.edited && value.is_favorited { + f.write_str(" ")?; + } + if value.is_favorited { + f.write_str("")?; + } + f.write_str("]")?; + } + + c!("36;1", f); + write!( + f, + " {}", + HumanTime::from( + Local + .timestamp_opt(value.timestamp, 0) + .single() + .expect("This should be valid") + ) + .to_text_en(Accuracy::Rough, Tense::Past) + )?; + c!("0", f); + + // c!("31;1", f); + // f.write_fmt(format_args!(" [{}]", comment.value.like_count))?; + // c!("0", f); + + f.write_str(":\n")?; + f.write_str(&ident)?; + + f.write_str(&value.text.replace('\n', &format!("\n{}", ident)))?; + f.write_str("\n")?; + + if !comment.replies.is_empty() { + let mut children = comment.replies.clone(); + children.sort_by(|a, b| a.value.timestamp.cmp(&b.value.timestamp)); + + for child in children { + format(&child, f, ident_count + 4)?; + } + } else { + f.write_str("\n")?; + } + + Ok(()) + } + + if !&self.vec.is_empty() { + let mut children = self.vec.clone(); + children.sort_by(|a, b| b.value.like_count.cmp(&a.value.like_count)); + + for child in children { + format(&child, f, 0)? + } + } + Ok(()) + } +} + +fn main() -> anyhow::Result<()> { + cli_log::init_cli_log!(); + let args: Option<String> = env::args().skip(1).last(); + let mut info_json: InfoJson = { + let status_path = if let Some(arg) = args { + PathBuf::from(arg) + } else { + status_path().context("Failed to get status path")? + }; + + let reader = + BufReader::new(File::open(&status_path).with_context(|| { + format!("Failed to open status file at {}", status_path.display()) + })?); + + serde_json::from_reader(reader)? + }; + + let base_comments = mem::take(&mut info_json.comments); + drop(info_json); + + let mut comments = Comments::new(); + base_comments.into_iter().for_each(|c| { + if let Parent::Id(id) = &c.parent { + comments.insert(&(id.clone()), CommentExt::from(c)); + } else { + comments.push(CommentExt::from(c)); + } + }); + + comments.vec.iter_mut().for_each(|comment| { + let replies = mem::take(&mut comment.replies); + let mut output_replies: Vec<CommentExt> = vec![]; + + let re = Regex::new(r"\u{200b}?(@[^\t\s]+)\u{200b}?").unwrap(); + for reply in replies { + if let Some(replyee_match) = re.captures(&reply.value.text){ + let full_match = replyee_match.get(0).expect("This always exists"); + let text = reply. + value. + text[0..full_match.start()] + .to_owned() + + + &reply + .value + .text[full_match.end()..]; + let text: &str = &text.trim().trim_matches('\u{200b}'); + + let replyee = replyee_match.get(1).expect("This should exist").as_str(); + + + if let Some(parent) = output_replies + .iter_mut() + .rev() + .flat_map(|com| &mut com.replies) + .flat_map(|com| &mut com.replies) + .flat_map(|com| &mut com.replies) + .filter(|com| com.value.author == replyee) + .last() + { + parent.replies.push(CommentExt::from(Comment { + text: text.to_owned(), + ..reply.value + })) + } else if let Some(parent) = output_replies + .iter_mut() + .rev() + .flat_map(|com| &mut com.replies) + .flat_map(|com| &mut com.replies) + .filter(|com| com.value.author == replyee) + .last() + { + parent.replies.push(CommentExt::from(Comment { + text: text.to_owned(), + ..reply.value + })) + } else if let Some(parent) = output_replies + .iter_mut() + .rev() + .flat_map(|com| &mut com.replies) + .filter(|com| com.value.author == replyee) + .last() + { + parent.replies.push(CommentExt::from(Comment { + text: text.to_owned(), + ..reply.value + })) + } else if let Some(parent) = output_replies.iter_mut() + .rev() + .filter(|com| com.value.author == replyee) + .last() + { + parent.replies.push(CommentExt::from(Comment { + text: text.to_owned(), + ..reply.value + })) + } else { + eprintln!( + "Failed to find a parent for ('{}') both directly and via replies! The reply text was:\n'{}'\n", + replyee, + reply.value.text + ); + output_replies.push(reply); + } + } else { + output_replies.push(reply); + } + } + comment.replies = output_replies; + }); + + let mut less = Command::new("less") + .args(["--raw-control-chars"]) + .stdin(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .expect("Should work"); + + let mut child = Command::new("fmt") + .args(["--uniform-spacing", "--split-only", "--width=90"]) + .stdin(Stdio::piped()) + .stderr(Stdio::inherit()) + .stdout(less.stdin.take().expect("Should be open")) + .spawn() + .expect("Failed to spawn child process"); + + let mut stdin = child.stdin.take().expect("Failed to open stdin"); + std::thread::spawn(move || { + stdin + .write_all(comments.to_string().as_bytes()) + .expect("Failed to write to stdin"); + }); + + let _ = less.wait().expect("Failed to read stdout"); + + Ok(()) +} + +#[cfg(test)] +mod test { + #[test] + fn test_string_replacement() { + let s = "A \n\nB\n\nC".to_owned(); + assert_eq!("A \n \n B\n \n C", s.replace('\n', "\n ")) + } +} diff --git a/sys/nixpkgs/pkgs/comments/update.sh b/sys/nixpkgs/pkgs/comments/update.sh new file mode 100755 index 00000000..2529167c --- /dev/null +++ b/sys/nixpkgs/pkgs/comments/update.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +cargo update && cargo upgrade + + +# vim: ft=sh |