Browse Source

feat: Add support for comment replies

Miguel Ángel Moreno 2 years ago
parent
commit
5fc4b8d6ed

+ 16 - 8
src/backend/tau/api/comments.clj

@@ -5,33 +5,41 @@
   (:import
    org.schabi.newpipe.extractor.NewPipe
    org.schabi.newpipe.extractor.Page
+   org.schabi.newpipe.extractor.ListExtractor
    org.schabi.newpipe.extractor.comments.CommentsInfoItem
    org.schabi.newpipe.extractor.comments.CommentsInfo))
 
 (defn get-comment-item
-  [item]
+  [item extractor]
   {:id (.getCommentId item)
    :text (.getCommentText item)
    :uploader-name (.getUploaderName item)
    :uploader-avatar (.getUploaderAvatarUrl item)
    :uploader-url (.getUploaderUrl item)
    :uploader-verified? (.isUploaderVerified item)
-   :upload-date (.getTextualUploadDate item)      
+   :upload-date (.getTextualUploadDate item)
    :like-count (when-not (= (.getLikeCount item) -1) (.getLikeCount item))
+   :reply-count (when-not (= (.getReplyCount item) -1) (.getReplyCount item))
    :hearted-by-uploader? (.isHeartedByUploader item)
    :pinned? (.isPinned item)
+   :stream-position (when-not (= (.getStreamPosition item) -1) (.getStreamPosition item))
    :replies (when (.getReplies item)
-              (j/from-java (.getReplies item)))})
+              (if extractor
+                (let [comments-page (.getPage extractor (.getReplies item))]
+                  {:next-page (when (.hasNextPage comments-page) (j/from-java (.getNextPage comments-page)))
+                   :items (map #(get-comment-item % extractor) (.getItems comments-page))})
+                (j/from-java (.getReplies item))))})
 
-(defn get-comment
+(defn get-comments
   ([url]
-   (let [info (CommentsInfo/getInfo (url-decode url))]
-     {:comments (map get-comment-item (.getRelatedItems info))
+   (let [info (CommentsInfo/getInfo (url-decode url))
+         extractor (.getCommentsExtractor info)]
+     {:comments (map #(get-comment-item % extractor) (.getRelatedItems info))
       :next-page (j/from-java (.getNextPage info))
       :disabled? (.isCommentsDisabled info)}))
   ([url page-url]
    (let [service (NewPipe/getServiceByUrl (url-decode url))
-         info (CommentsInfo/getMoreItems service url (Page. (url-decode page-url)))]
-     {:comments (map get-comment-item (.getItems info))
+         info (CommentsInfo/getMoreItems service (url-decode url) (Page. (url-decode page-url)))]
+     {:comments (map #(get-comment-item % nil) (.getItems info))
       :next-page (j/from-java (.getNextPage info))
       :disabled? false})))

+ 2 - 2
src/backend/tau/handler.clj

@@ -48,8 +48,8 @@
 (defn comments
   [{{:keys [url]} :path-params {:strs [nextPage]} :query-params}]
   (response (if nextPage
-              (comments/get-comment url nextPage)
-              (comments/get-comment url))))
+              (comments/get-comments url nextPage)
+              (comments/get-comments url))))
 
 (defn services
   [_]

+ 28 - 11
src/frontend/tau/components/comments.cljs

@@ -9,19 +9,21 @@
 (defn comment-item
   [{:keys [id text uploader-name uploader-avatar uploader-url
            upload-date uploader-verified? like-count hearted-by-uploader?
-           pinned? replies key]} author-name author-avatar]
-  [:div.flex.my-4
+           pinned? replies reply-count key show-replies author-name author-avatar]}]
+  [:div.flex.my-4 {:key key}
    (when uploader-avatar
      [:div.flex.items-center.py-3.box-border.h-12
-      [:div.w-12
-       [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url}) :title name}
-        [:img.rounded-full.object-cover.min-w-full.min-h-full {:src uploader-avatar}]]]])
+      (when uploader-url
+        [:div.w-12
+         [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url}) :title uploader-name}
+          [:img.rounded-full.object-cover.min-w-full.min-h-full {:src uploader-avatar}]]])])
    [:div.ml-4
     [:div.flex.items-center
      (when pinned?
        [:i.fa-solid.fa-thumbtack.mr-2.text-xs])
-     [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url}) :title name}
-      [:h1.text-gray-300.font-bold uploader-name]]
+     (when uploader-name
+       [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url}) :title uploader-name}
+        [:h1.text-gray-300.font-bold uploader-name]])
      (when uploader-verified?
        [:i.fa-solid.fa-circle-check.ml-2])]
     [:div.my-2
@@ -31,7 +33,7 @@
       [:p (if (-> upload-date js/Date.parse js/isNaN)
             upload-date
             (timeago/format upload-date))]]
-     (when like-count
+     (when (and like-count (> like-count 0))
        [:div.flex.items-center.my-2
         [:i.fa-solid.fa-thumbs-up.text-xs]
         [:p.mx-1 like-count]])
@@ -39,7 +41,17 @@
        [:div.relative.w-4.h-4.mx-2
         [:i.fa-solid.fa-heart.absolute.-bottom-1.-right-1.text-xs.text-red-500]
         [:img.rounded-full.object-covermax-w-full.min-h-full
-         {:src author-avatar :title (str author-name " hearted this comment")}]])]]])
+         {:src author-avatar :title (str author-name " hearted this comment")}]])]
+    [:div.flex.ml-8.items-center.cursor-pointer
+     {:on-click #(rf/dispatch [::events/toggle-comment-replies id])}
+     (when replies
+       (if show-replies
+         [:<>
+          [:p.font-bold "Hide replies"]
+          [:i.fa-solid.fa-turn-up.mx-2.text-xs]]
+         [:<>
+          [:p.font-bold (str reply-count (if (= reply-count 1) " reply" " replies"))]
+          [:i.fa-solid.fa-turn-down.mx-2.text-xs]]))]]])
 
 (defn comments
   [{:keys [comments next-page disabled?]} author-name author-avatar url]
@@ -47,8 +59,13 @@
         service-color @(rf/subscribe [:service-color])]
     [:div.flex.flex-col
      [:div
-      (for [[i comment] (map-indexed vector comments)]
-        [comment-item (assoc comment :key i) author-name author-avatar])]
+      (for [[i {:keys [replies show-replies] :as comment}] (map-indexed vector comments)]
+        [:div.flex.flex-col {:key i}
+         [comment-item (assoc comment :key i :author-name author-name :author-avatar author-avatar)]
+         (when (and replies show-replies)
+           [:div {:style {:marginLeft "32px"}}
+            (for [[i reply] (map-indexed vector (:items replies))]
+              [comment-item (assoc reply :key i :author-name author-name :author-avatar author-avatar)])])])]
      (when (:url next-page)
        (if pagination-loading?
          (loading/loading-icon service-color)

+ 11 - 1
src/frontend/tau/events.cljs

@@ -210,9 +210,19 @@
 
 (rf/reg-event-db
  ::toggle-comments
- (fn [db [_ res]]
+ (fn [db _]
    (assoc-in db [:stream :show-comments] (not (-> db :stream :show-comments)))))
 
+(rf/reg-event-db
+ ::toggle-comment-replies
+ (fn [db [_ comment-id]]
+   (update-in db [:stream :comments-page :comments]
+              (fn [comments]
+                (map #(if (= (:id %) comment-id)
+                        (assoc % :show-replies (not (:show-replies %)))
+                        %)
+                     comments)))))
+
 (rf/reg-event-db
  ::load-paginated-comments
  (fn [db [_ res]]