Sonarr works again

This commit is contained in:
Kiran Shila
2022-01-04 08:48:50 -08:00
parent adaedbb417
commit 8089472c6a
3 changed files with 193 additions and 1 deletions

View File

@@ -0,0 +1,76 @@
(ns doplarr.backends.sonarr
(:require
[taoensso.timbre :refer [warn fatal]]
[config.core :refer [env]]
[doplarr.utils :as utils]
[fmnoise.flow :refer [then else]]
[doplarr.backends.sonarr.impl :as impl]
[clojure.core.async :as a]))
(defn search [term]
(utils/request-and-process-body
impl/GET
#(mapv utils/process-search-result %)
"/series/lookup"
{:query-params {:term term}}))
(defn additional-options [result]
(a/go
(let [quality-profiles (a/<! (impl/quality-profiles))
language-profiles (a/<! (impl/language-profiles))
details (a/<! (impl/get-from-tvdb (:tvdb-id result)))
seasons (->> (:seasons details)
(filter #(pos? (:season-number %)))
(map #(let [ssn (:season-number %)]
(hash-map :id ssn :name (str ssn)))))
{:keys [sonarr/language-profile
sonarr/quality-profile
partial-seasons]} env
default-profile-id (utils/profile-name-id quality-profiles quality-profile)
default-language-id (utils/profile-name-id language-profiles language-profile)]
(when (and quality-profile (nil? default-profile-id))
(warn "Default quality profile in config doesn't exist in backend, check spelling"))
(when (and language-profile (nil? default-language-id))
(warn "Default language profile in config doesn't exist in backend, check spelling"))
{:season (cond
(= 1 (count seasons)) (:id (first seasons))
(false? partial-seasons) -1
:else (conj seasons {:name "All Seasons" :id -1}))
:quality-profile-id (cond
quality-profile default-profile-id
(= 1 (count quality-profiles)) (:id (first quality-profiles))
:else quality-profiles)
:language-profile-id (cond
language-profile default-language-id
(= 1 (count language-profiles)) (:id (first language-profiles))
:else language-profiles)})))
(defn request-embed [{:keys [title quality-profile-id language-profile-id tvdb-id season]}]
(a/go
(let [quality-profiles (a/<! (impl/quality-profiles))
language-profiles (a/<! (impl/language-profiles))
details (a/<! (impl/get-from-tvdb tvdb-id))]
{:title title
:overview (:overview details)
:poster (:remote-poster details)
:media-type :series
:season season
:request-formats [""]
:quality-profile (:name (first (filter #(= quality-profile-id (:id %)) quality-profiles)))
:language-profile (:name (first (filter #(= language-profile-id (:id %)) language-profiles)))})))
(defn request [payload]
(a/go (let [details (a/<! (if-let [id (:id payload)]
(impl/get-from-id id)
(impl/get-from-tvdb (:tvdb-id payload))))
status (impl/status details (:season payload))
request-payload (impl/request-payload payload details)]
(if status
status
(->> (a/<! ((if (:id payload) impl/PUT impl/POST) "/series" {:form-params (utils/to-camel request-payload)
:content-type :json}))
(then (fn [_]
(when-let [id (:id payload)]
(if (= -1 (:season payload))
(impl/search-series id)
(impl/search-season id (:season payload)))))))))))

View File

@@ -0,0 +1,109 @@
(ns doplarr.backends.sonarr.impl
(:require
[clojure.core.async :as a]
[config.core :refer [env]]
[fmnoise.flow :as flow :refer [then]]
[doplarr.utils :as utils]))
(def base-url (delay (str (:sonarr/url env) "/api/v3")))
(def api-key (delay (:sonarr/api env)))
(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 PUT [endpoint & [params]]
(utils/http-request :put (str @base-url endpoint) @api-key params))
(def rootfolder (delay (a/<!! (utils/request-and-process-body GET #(get (first %) "path") "/rootfolder"))))
(defn quality-profiles []
(utils/request-and-process-body
GET
#(map utils/process-profile %)
"/qualityProfile"))
(defn language-profiles []
(utils/request-and-process-body
GET
#(map utils/process-profile %)
"/languageProfile"))
(defn get-from-tvdb [tvdb-id]
(utils/request-and-process-body
GET
(comp utils/from-camel first)
"/series/lookup"
{:query-params {:term (str "tvdbId:" tvdb-id)}}))
(defn get-from-id [id]
(utils/request-and-process-body
GET
utils/from-camel
(str "/series/" id)))
(defn execute-command [command & {:as opts}]
(a/go
(->> (a/<! (POST "/command" {:form-params (merge {:name command} opts)
:content-type :json}))
(then (constantly nil)))))
(defn search-season [series-id season]
(a/go
(->> (a/<! (execute-command "SeasonSearch" {:seriesId series-id
:seasonNumber season})))
(then (constantly nil))))
(defn search-series [series-id]
(a/go
(->> (a/<! (execute-command "SeriesSearch" {:seriesId series-id})))
(then (constantly nil))))
(defn status [details season]
(if (= -1 season)
nil ; FIXME All season status
(let [ssn (->> (:seasons details)
(filter (comp (partial = season) :season-number))
first)]
(when-let [stats (:statistics ssn)]
(when (:monitored ssn)
(cond
(> 100.0 (:percent-of-episodes stats)) :processing
:else :available))))))
(defn generate-seasons [request-seasons total-seasons]
(into []
(conj
(for [season (range 1 (inc total-seasons))]
{:season-number season
:monitored (contains? request-seasons season)})
{:season-number 0 :monitored false})))
(defn generate-request-seasons
[details season]
(if (= -1 season)
(into #{} (range 1 (inc (count (:seasons details)))))
(if (:id details)
(conj (->> (:seasons details)
(keep #(when (:monitored %) (:season-number %)))
(into #{}))
season)
#{season})))
(defn request-payload [payload details]
(let [seasons (-> (generate-request-seasons details (:season payload))
(generate-seasons (count (:seasons details))))]
(if (:id payload)
(assoc details
:seasons seasons
:quality-profile-id (:quality-profile-id payload))
(-> payload
(assoc :monitored true
:seasons seasons
:root-folder-path @rootfolder
:add-options {:ignore-episodes-with-files true
:search-for-missing-episodes true})
(dissoc :season
:format)))))

View File

@@ -21,6 +21,10 @@
(spec/def :discord/max-results pos-int?)
(spec/def :radarr/quality-profile string?)
(spec/def :sonarr/quality-profile string?)
(spec/def :sonarr/language-profile string?)
(spec/def ::partial-seasons boolean?)
(defn when-req [pred spec]
(spec/nonconforming
@@ -36,7 +40,10 @@
(spec/keys :req [:discord/token]
:opt [:discord/role-id
:discord/max-results
:radarr/quality-profile])
:radarr/quality-profile
:sonarr/quality-profile
:sonarr/language-profile
::partial-seasons])
#(some (partial contains? %) [:sonarr/url
:radarr/url])
(matched-keys :sonarr/url :sonarr/api)