about summary refs log tree commit diff stats
path: root/yt/src/comments/comment.rs
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-13 20:54:49 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-13 20:56:40 +0200
commit69145b4deed4fe512239a9f88e6af69d3b8c0309 (patch)
tree7643edd350c1cec75f91e0982ffd3c840f8661fb /yt/src/comments/comment.rs
parentbuild(treewide): Update (diff)
downloadyt-69145b4deed4fe512239a9f88e6af69d3b8c0309.zip
feat({yt_dlp,yt}): Migrate from pyo3 to rustpython
That allows us to avoid cpython's GIL and gives us full ability to
leverage async/concurrent code to speed up python operations.

I have also taken the opportunity to change the `InfoJson` struct to an
untyped json value, as that is what it actually is.
Diffstat (limited to 'yt/src/comments/comment.rs')
-rw-r--r--yt/src/comments/comment.rs89
1 files changed, 88 insertions, 1 deletions
diff --git a/yt/src/comments/comment.rs b/yt/src/comments/comment.rs
index 6b8cf73..5bc939c 100644
--- a/yt/src/comments/comment.rs
+++ b/yt/src/comments/comment.rs
@@ -9,7 +9,94 @@
 // You should have received a copy of the License along with this program.
 // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-use yt_dlp::wrapper::info_json::Comment;
+use serde::{Deserialize, Deserializer, Serialize};
+use url::Url;
+
+#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, PartialOrd, Ord)]
+#[serde(from = "String")]
+#[serde(deny_unknown_fields)]
+pub enum Parent {
+    Root,
+    Id(String),
+}
+
+impl Parent {
+    #[must_use]
+    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, Serialize, Clone, Eq, PartialEq, PartialOrd, Ord)]
+#[serde(from = "String")]
+#[serde(deny_unknown_fields)]
+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, Serialize, Clone, Eq, PartialEq, PartialOrd, Ord)]
+#[allow(clippy::struct_excessive_bools)]
+pub struct Comment {
+    pub id: Id,
+    pub text: String,
+    #[serde(default = "zero")]
+    pub like_count: u32,
+    pub is_pinned: bool,
+    pub author_id: String,
+    #[serde(default = "unknown")]
+    pub author: String,
+    pub author_is_verified: bool,
+    pub author_thumbnail: Url,
+    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: Option<Url>,
+    pub author_is_uploader: bool,
+    pub is_favorited: bool,
+}
+
+fn unknown() -> String {
+    "<Unknown>".to_string()
+}
+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, Clone)]
 #[allow(clippy::module_name_repetitions)]