Overseerr is searching now

This commit is contained in:
Kiran Shila
2022-01-05 13:07:49 -08:00
parent b965755b5b
commit 1d16f87d50
7 changed files with 172 additions and 11 deletions

View File

@@ -0,0 +1,16 @@
(ns doplarr.backends.overseerr
(:require
[doplarr.backends.overseerr.impl :as impl]
[doplarr.utils :as utils]))
(defn search [term media-type]
(utils/request-and-process-body
impl/GET
(partial impl/process-search-result (name media-type))
(str "/search?query=" term)))
(defn additional-options [result])
(defn request-embed [] ["" "4K"])
(defn request [payload])

View File

@@ -0,0 +1,130 @@
(ns doplarr.backends.overseerr.impl
(:require
[taoensso.timbre :refer [fatal]]
[com.rpl.specter :as s]
[clojure.core.async :as a]
[config.core :refer [env]]
[fmnoise.flow :as flow :refer [then else]]
[doplarr.utils :as utils]))
(def base-url (delay (str (:overseerr/url env) "/api/v1")))
(def api-key (delay (:overseerr/api env)))
(def poster-path "https://image.tmdb.org/t/p/w500")
(def status [:unknown :pending :processing :partially-available :available])
(defn GET [endpoint & [params]]
(utils/http-request :get (str @base-url endpoint) @api-key params))
(defn POST [endpoint & [params]]
(utils/http-request :post (str @base-url endpoint) @api-key params))
(defn backend-4k? [media-type]
(a/go
(->> (a/<! (GET (str "/settings/" (if (= media-type "tv") "sonarr" "radarr"))))
(then #(->> (:body %)
(map :is4k)
(some identity)))
(else #(fatal % "Exception on checking Overseeerr 4K backend support")))))
(defn parse-year [result]
(.getYear (java.time.LocalDate/parse
(if (empty? (or (:first-air-date result)
(:release-date result)))
"0000-01-01"
(or (:first-air-date result)
(:release-date result))))))
(defn process-search-result [media-type-str body]
(->> (utils/from-camel body)
(s/select [:results
s/ALL
(s/selected? :media-type (s/pred= media-type-str))
(s/view #(assoc % :year (parse-year %)))
(s/submap [:title :id :year])])))
(defn num-users []
(a/go
(->> (a/<! (GET "/user" {:query-params {:take 1}}))
(then #(s/select-one [:body :pageInfo :results] %))
(else #(fatal % "Exception on querying Overseerr users")))))
(defn all-users []
(a/go
(->> (a/<! (GET "/user" {:query-params {:take (a/<! (num-users))}}))
(then #(->> (s/select-one [:body :results] %)
(map :id)
(into [])))
(else #(fatal % "Exception on querying Overseerr users")))))
(defn discord-id [ovsr-id]
(a/go
(->> (a/<! (GET (str "/user/" ovsr-id)))
(then #(s/select-one [:body :settings :discordId] %))
(else #(fatal % "Exception on querying Overseerr discord id")))))
(defn discord-users []
(a/go-loop [ids (a/<! (all-users))
users {}]
(if (empty? ids)
users
(let [id (first ids)]
(recur (rest ids) (assoc users (a/<! (discord-id id)) id))))))
(defn details
([selection] (details (:id selection) (:mediaType selection)))
([id media-type]
(a/go
(->> (a/<! (GET (str "/" media-type "/" id)))
(then :body)
(else #(fatal % "Error requesting details on selection from Overseerr"))))))
(defn series-status [selection & {:keys [is4k]}]
(when-let [info (:mediaInfo selection)]
(status (dec ((if is4k :status4k :status) info)))))
(defn season-status [selection & {:keys [season is4k]}]
(when-let [ss (series-status selection :is4k is4k)]
(if (= ss :partially-available)
(when-let [seasons (seq (:seasons (:mediaInfo selection)))]
(status (dec ((if is4k :status4k :status) (nth seasons (dec season))))))
ss)))
(defn movie-status [selection & {:keys [is4k]}]
(when-let [info (:mediaInfo selection)]
(status (dec ((if is4k :status4k :status) info)))))
(defn selection-to-request [selection & {:keys [season is4k]}]
(cond-> {:mediaType (:mediaType selection)
:mediaId (:id selection)
:is4k is4k}
(= "tv" (:mediaType selection)) (assoc :seasons (if (= -1 season)
(into [] (range 1 (inc (:seasonCount selection))))
[season]))))
(defn selection-to-embedable [selection]
(as-> selection s
(assoc s :seasonCount (:numberOfSeasons s))
(assoc s :description (:overview s))
(assoc s :remotePoster (str poster-path (:posterPath s)))))
(defn post-process-selection [selection]
(a/go
(let [details (a/<! (details selection))
fourK-backend? (a/<! (backend-4k? (:mediaType selection)))]
(selection-to-embedable (merge details selection {:backend-4k fourK-backend?})))))
(defn request [body & {:keys [ovsr-id]}]
(a/go
(->> (a/<! (POST "/request" {:form-params body
:content-type :json
:headers {"X-API-User" (str ovsr-id)}}))
(then (constantly nil)))))
(defn partial-seasons? []
(a/go
(->> (a/<! (GET "/settings/main"))
(then #(->> (:body %)
:partialRequestsEnabled))
(else #(fatal % "Exception testing for partial seasons")))))

View File

@@ -7,7 +7,7 @@
[doplarr.backends.radarr.impl :as impl]
[clojure.core.async :as a]))
(defn search [term]
(defn search [term _]
(utils/request-and-process-body
impl/GET
#(map utils/process-search-result %)

View File

@@ -7,7 +7,7 @@
[doplarr.backends.sonarr.impl :as impl]
[clojure.core.async :as a]))
(defn search [term]
(defn search [term _]
(utils/request-and-process-body
impl/GET
#(mapv utils/process-search-result %)

View File

@@ -34,7 +34,7 @@
(cond-> #{}
(:radarr/url env) (conj :radarr)
(:sonarr/url env) (conj :sonarr)
(:overserr/url env) (conj :overseerr)
(:overseerr/url env) (conj :overseerr)
(:readarr/url env) (conj :readarr)
(:lidarr/url env) (conj :lidarr)))

View File

@@ -9,7 +9,7 @@
[discljord.messaging :as m]
[clojure.string :as str]
[doplarr.state :as state]
[doplarr.utils :as utils]))
[doplarr.utils :as utils :refer [log-on-error]]))
(def channel-timeout 600000)
@@ -27,9 +27,11 @@
(else #(fatal % "Error in interaction ack")))
; Search for results
(info "Performing search for" (name media-type) query)
(let [results (->> (a/<! ((utils/media-fn media-type "search") query))
(take (:max-results env 10))
(into []))]
(let [results (->> (log-on-error
(a/<! ((utils/media-fn media-type "search") query media-type))
"Exception from search")
(then #(->> (take (:max-results env 10) %)
(into []))))]
; Setup ttl cache entry
(swap! state/cache assoc uuid {:results results
:media-type media-type
@@ -44,7 +46,9 @@
(let [{:keys [messaging bot-id]} @state/discord
{:keys [media-type token payload]} (get @state/cache uuid)]
(if (empty? pending-opts)
(let [embed (a/<! ((utils/media-fn media-type "request-embed") payload))]
(let [embed (log-on-error
(a/<! ((utils/media-fn media-type "request-embed") payload))
"Exception from request-embed")]
(->> @(m/edit-original-interaction-response! messaging bot-id token (discord/request embed uuid))
(else #(fatal % "Error in sending request embed"))))
(let [[op options] (first pending-opts)]
@@ -57,7 +61,9 @@
(a/go
(let [{:keys [results media-type]} (get @state/cache uuid)
result (nth results (discord/dropdown-result interaction))
add-opts (a/<! ((utils/media-fn media-type "additional-options") result))
add-opts (log-on-error
(a/<! ((utils/media-fn media-type "additional-options") result))
"Exception thrown from additional-options")
pending-opts (->> add-opts
(filter #(seq? (second %)))
(into {}))
@@ -80,8 +86,10 @@
{:keys [payload media-type token]} (get @state/cache uuid)]
(letfn [(msg-resp [msg] (->> @(m/edit-original-interaction-response! messaging bot-id token (discord/content-response msg))
(else #(fatal % "Error in message response"))))]
(->> (a/<!! ((utils/media-fn media-type "request")
(assoc payload :format (keyword format))))
(->> (log-on-error
(a/<!! ((utils/media-fn media-type "request")
(assoc payload :format (keyword format))))
"Exception from request")
(then (fn [status]
(case status
:unauthorized (msg-resp "You do not have an associated account in the request backend")

View File

@@ -77,3 +77,10 @@
(symbol (str "doplarr.backends." (name (config/available-backed-for-media
media)))
f)))
(defmacro log-on-error [expr msg]
`(try
~expr
(catch Exception e#
(fatal e# ~msg)
(throw e#))))