mirror of
https://github.com/kiranshila/Doplarr.git
synced 2026-04-05 00:44:05 -04:00
Sonarr works again
This commit is contained in:
76
src/doplarr/backends/sonarr.clj
Normal file
76
src/doplarr/backends/sonarr.clj
Normal 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)))))))))))
|
||||
109
src/doplarr/backends/sonarr/impl.clj
Normal file
109
src/doplarr/backends/sonarr/impl.clj
Normal 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)))))
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user