diff --git a/src/main/backend/core.clj b/src/main/backend/core.clj index 178c95d..323d10f 100644 --- a/src/main/backend/core.clj +++ b/src/main/backend/core.clj @@ -10,10 +10,12 @@ (ring/ring-handler (ring/router [["/hp/:id" {:parameters {:path {:id int?}} - :get {:handler hugo/build-hugo-post}}] + :get {:handler hugo/build-hugo-post}}] ["/api" ["/hp/:id" {:parameters {:path {:id int?}} - :get {:handler handlers/build-api-hu-post}}]]]) + :get {:handler handlers/build-api-hu-post}}] + ["/hq/:id" {:parameters {:path {:id int?}} + :get {:handler handlers/build-api-hu-question}}]]]) (ring/routes (ring/create-resource-handler {:path "/"}) (ring/create-default-handler diff --git a/src/main/backend/handlers.clj b/src/main/backend/handlers.clj index bb43c52..fd85515 100644 --- a/src/main/backend/handlers.clj +++ b/src/main/backend/handlers.clj @@ -2,7 +2,7 @@ (:require [clojure.string :as str] [babashka.http-client :as client] [ring.util.codec :refer [url-decode]] - [cheshire.core :refer [generate-string]]) + [cheshire.core :refer [generate-string parse-string]]) (:import [org.jsoup Jsoup])) @@ -86,3 +86,83 @@ {:content-type {"Content-Type" "application/json; charset=utf-8"} :replace-str "#/item/" :wrap-fn wrap-json}))) + +(defn build-answer + [m] + (if (contains? m "target") + (into {} + {:author {:avatar_url (get-in m ["target" "author" "avatar_url"] ) + :url_token (get-in m ["target" "author" "url_token"] ) + :name (get-in m ["target" "author" "name"])} + :id (get-in m ["target" "id"]) + :content (get-in m ["target" "content"]) + :created_time (get-in m ["target" "created_time"]) + :updated_time (get-in m ["target" "updated_time"]) + :comment_count (get-in m ["target" "comment_count"]) + :thanks_count (get-in m ["target" "thanks_count"])}) + + (into {} + {:author {:avatar_url (get-in m ["author" "avatarUrl"]) + :url_token (get-in m ["author" "urlToken"]) + :name (get-in m ["author" "name"])} + :id (get m "id") + :content (get m "content") + :created_time (get m "createdTime") + :updated_time (get m "updatedTime") + :comment_count (get m "commentCount") + :thanks_count (get m "thanksCount")}))) + +(defn build-question + [m] + (into {} + {:title (get m "title") + :detail (get m "detail") + :voteup_count (get m "voteupCount") + :visit_count (get m "visitCount") + :answer_count (get m "answerCount") + :created_time (get m "created") + :updated_time (get m "updatedTime")})) + +(defn process-hu-questiion + [question-json {:keys [content-type wrap-fn]}] + + {:status 200 + :headers content-type + :body (wrap-fn + (merge + {:question (build-question (val (first (get-in question-json ["initialState" "entities" "questions"]))))} + {:answers (mapv build-answer (vals (get-in question-json ["initialState" "entities" "answers"])))}))}) + +(defn fetch-hu-question + [question-id params] + (let [question-url (str/join ["https://www.zhihu.com/question/" + question-id]) + question-page (-> (client/get question-url) :body Jsoup/parse) + question-json (-> (.getElementById question-page "js-initialData") + .firstChild + .toString + parse-string) + question-error? (= (get question-json "subAppName") "errorpage")] + + (if question-error? + {:status 404 + :headers (:content-type params) + :body {:content "Not Found" + :title "Not Found"}} + + (process-hu-questiion question-json params)))) + +(defn fetch-hu-answers + [question-id params] + (let [question-url (str/join ["https://www.zhihu.com/api/v4/questions/" + question-id + "/feeds?cursor=&include=data%5B%2A%5D.is_normal%2Cadmin_closed_comment%2Cis_collapsed%2Cannotation_action%2Cannotation_detail%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cattachment%2Cvoteup_count%2Ccomment_permission%2Ccreated_time%2Cupdated_time%2Creview_info%2Crelevant_info%2Cquestion%2Cexcerpt%2Cis_labeled%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%3Bdata%5B%2A%5D.mark_infos%5B%2A%5D.url%3Bdata%5B%2A%5D.author.follower_count%2Cvip_info%2Cbadge%5B%2A%5D.topics%3Bdata%5B%2A%5D.settings.table_of_content.enabled&limit=5&offset=0&order=default&platform=desktop&session_id="]) + question-json (-> (client/get question-url) :body parse-string)] + question-json)) + +(defn build-api-hu-question + [request] + (let [question-id (-> request :path-params :id)] + (fetch-hu-question question-id + {:content-type {"Content-Type" "application/json; charset=utf-8"} + :wrap-fn wrap-json})))