mirror of
https://github.com/kiranshila/Doplarr.git
synced 2026-08-02 02:08:38 -04:00
Spec-ing out everything and codifying interfaces
WIP
This commit is contained in:
7
deps.edn
7
deps.edn
@@ -5,11 +5,14 @@
|
||||
yogthos/config {:mvn/version "1.1.8"}
|
||||
com.rpl/specter {:mvn/version "1.1.3"}
|
||||
ch.qos.logback/logback-classic {:mvn/version "1.2.5"}
|
||||
org.suskalo/discljord {:mvn/version "1.3.0-SNAPSHOT"}
|
||||
org.suskalo/discljord {:mvn/version "1.3.0-RC2"}
|
||||
org.clojure/core.async {:mvn/version "1.3.618"}
|
||||
cheshire/cheshire {:mvn/version "5.10.1"}
|
||||
fmnoise/flow {:mvn/version "4.1.0"}
|
||||
hato/hato {:mvn/version "0.8.2"}}
|
||||
hato/hato {:mvn/version "0.8.2"}
|
||||
camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.2"}
|
||||
org.clojure/alpha.spec {:git/url "https://github.com/clojure/spec-alpha2.git"
|
||||
:sha "c087ded910b3532a938b37e853df79fc3b9c48c1"}}
|
||||
|
||||
:jvm-opts ["-Dconfig=config.edn"]
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
(ns doplarr.arr-utils
|
||||
(:require
|
||||
[clojure.tools.logging :as log]
|
||||
[clojure.core.async :as a]
|
||||
[fmnoise.flow :as flow :refer [then else]]
|
||||
[hato.client :as hc]))
|
||||
|
||||
(defn fatal-error [ex]
|
||||
(log/fatal ex)
|
||||
#_(System/exit -1))
|
||||
|
||||
(defn deep-merge [a & maps]
|
||||
(if (map? a)
|
||||
(apply merge-with deep-merge a maps)
|
||||
(apply merge-with deep-merge maps)))
|
||||
|
||||
(defn http-request [method url key & [params]]
|
||||
(let [chan (a/chan)
|
||||
put-close #(do
|
||||
(a/put! chan %)
|
||||
(a/close! chan))]
|
||||
(hc/request
|
||||
(deep-merge
|
||||
{:method method
|
||||
:url url
|
||||
:as :json
|
||||
:async? true
|
||||
:headers {"X-API-Key" key}}
|
||||
params)
|
||||
put-close
|
||||
put-close)
|
||||
chan))
|
||||
|
||||
(defn rootfolder [base-url key]
|
||||
(a/go
|
||||
(->> (a/<! (http-request
|
||||
:get
|
||||
(str base-url "/rootfolder")
|
||||
key))
|
||||
(then (comp :path first :body))
|
||||
(else fatal-error))))
|
||||
|
||||
(defn quality-profile-data [profile]
|
||||
{:name (:name profile)
|
||||
:id (:id profile)})
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns doplarr.overseerr
|
||||
(ns doplarr.backends.overseerr.impl
|
||||
(:require
|
||||
[com.rpl.specter :as s]
|
||||
[clojure.core.async :as a]
|
||||
74
src/doplarr/backends/radarr/impl.clj
Normal file
74
src/doplarr/backends/radarr/impl.clj
Normal file
@@ -0,0 +1,74 @@
|
||||
(ns doplarr.backends.radarr.impl
|
||||
(:require
|
||||
[config.core :refer [env]]
|
||||
[doplarr.utils :as utils]
|
||||
[doplarr.backends.radarr.specs :as specs]
|
||||
[clojure.core.async :as a]
|
||||
[clojure.spec.alpha :as spec]
|
||||
[doplarr.backends.specs :as bs]))
|
||||
|
||||
(def base-url (delay (str (:radarr-url env) "/api/v3")))
|
||||
(def api-key (delay (:radarr-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))
|
||||
|
||||
(def rootfolder (delay (a/<!! (utils/request-and-process-body GET #(get (first %) "path") "/rootfolder"))))
|
||||
|
||||
(defn search [term]
|
||||
(utils/request-and-process-body
|
||||
GET
|
||||
#(into [] (map utils/process-search-result %))
|
||||
"/movie/lookup"
|
||||
{:query-params {:term term}}))
|
||||
|
||||
(defn quality-profiles []
|
||||
(utils/request-and-process-body
|
||||
GET
|
||||
#(into [] (map utils/process-quality-profile %))
|
||||
"/qualityProfile"))
|
||||
|
||||
(defn status [movie & _]
|
||||
(cond
|
||||
(and (:has-file movie)
|
||||
(:is-available movie)
|
||||
(:monitored movie)) :available
|
||||
(and (not (:has-file movie))
|
||||
(:is-available movie)
|
||||
(:monitored movie)) :processing
|
||||
:else nil))
|
||||
|
||||
(defn request-payload [result quality-profile-id]
|
||||
(merge result
|
||||
{:quality-profile-id quality-profile-id
|
||||
:monitored true
|
||||
:rootFolderPath @rootfolder
|
||||
:add-options {:search-for-movie true}}))
|
||||
|
||||
(spec/fdef request-payload :args (spec/cat :arg ::bs/result :arg ::bs/quality-profile-id))
|
||||
|
||||
(defn request [payload]
|
||||
(utils/request-and-process-body
|
||||
POST
|
||||
(constantly nil)
|
||||
"/movie"
|
||||
{:form-params (utils/to-camel payload)
|
||||
:content-type :json}))
|
||||
|
||||
(spec/fdef request :args (spec/cat :arg ::specs/payload))
|
||||
|
||||
(def payload {:title "Making 'The Matrix'"
|
||||
:tmdb-id 684431
|
||||
:quality-profile-id 1
|
||||
:root-folder-path (a/<!! (rootfolder))})
|
||||
9
src/doplarr/backends/radarr/specs.clj
Normal file
9
src/doplarr/backends/radarr/specs.clj
Normal file
@@ -0,0 +1,9 @@
|
||||
(ns doplarr.backends.radarr.specs
|
||||
(:require
|
||||
[clojure.spec.alpha :as spec]
|
||||
[doplarr.backends.specs :as bs]))
|
||||
|
||||
(spec/def ::payload (spec/keys :req-un [::bs/title
|
||||
::bs/tmdb-id
|
||||
::bs/root-folder-path
|
||||
::bs/quality-profile-id]))
|
||||
@@ -1,10 +1,10 @@
|
||||
(ns doplarr.sonarr
|
||||
(ns doplarr.backends.sonarr.impl
|
||||
(:require
|
||||
[com.rpl.specter :as s]
|
||||
[clojure.core.async :as a]
|
||||
[config.core :refer [env]]
|
||||
[fmnoise.flow :as flow :refer [then else]]
|
||||
[doplarr.arr-utils :as utils]))
|
||||
[doplarr.utils :as utils]))
|
||||
|
||||
(def base-url (delay (str (:sonarr-url env) "/api/v3")))
|
||||
(def api-key (delay (:sonarr-api env)))
|
||||
2
src/doplarr/backends/sonarr/specs.clj
Normal file
2
src/doplarr/backends/sonarr/specs.clj
Normal file
@@ -0,0 +1,2 @@
|
||||
(ns doplarr.backends.sonarr.specs
|
||||
(:require [clojure.spec.alpha :as spec]))
|
||||
14
src/doplarr/backends/specs.clj
Normal file
14
src/doplarr/backends/specs.clj
Normal file
@@ -0,0 +1,14 @@
|
||||
(ns doplarr.backends.specs
|
||||
(:require [clojure.spec.alpha :as spec]))
|
||||
|
||||
(spec/def ::title string?)
|
||||
(spec/def ::year int?)
|
||||
(spec/def ::id int?)
|
||||
(spec/def ::tmdb-id int?)
|
||||
(spec/def ::tvdb-id int?)
|
||||
(spec/def ::root-folder-path string?)
|
||||
(spec/def ::quality-profile-id (spec/and int? pos?))
|
||||
|
||||
(spec/def ::result (spec/keys
|
||||
:req-un [::title ::year]
|
||||
:opt-un [::id ::tvdb-id ::tmdb-id]))
|
||||
@@ -1,61 +0,0 @@
|
||||
(ns doplarr.radarr
|
||||
(:require
|
||||
[config.core :refer [env]]
|
||||
[doplarr.arr-utils :as utils]
|
||||
[fmnoise.flow :as flow :refer [then else]]
|
||||
[clojure.core.async :as a]))
|
||||
|
||||
(def base-url (delay (str (:radarr-url env) "/api/v3")))
|
||||
(def api-key (delay (:radarr-api env)))
|
||||
|
||||
(defn rootfolder [] (utils/rootfolder @base-url @api-key))
|
||||
|
||||
(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 search [term]
|
||||
(a/go
|
||||
(->> (a/<! (GET "/movie/lookup" {:query-params {:term term}}))
|
||||
(then :body)
|
||||
(else utils/fatal-error))))
|
||||
|
||||
(defn quality-profiles []
|
||||
(a/go
|
||||
(->> (a/<! (GET "/qualityProfile"))
|
||||
(then #(->> (:body %)
|
||||
(map utils/quality-profile-data)))
|
||||
(else utils/fatal-error))))
|
||||
|
||||
(defn request [movie & {:keys [profile-id]}]
|
||||
(a/go
|
||||
(->> (a/<! (POST
|
||||
"/movie"
|
||||
{:form-params (merge movie
|
||||
{:qualityProfileId profile-id
|
||||
:monitored true
|
||||
:minimumAvailability "announced"
|
||||
:rootFolderPath (a/<! (rootfolder))
|
||||
:addOptions {:searchForMovie true}})
|
||||
:content-type :json}))
|
||||
(then (constantly nil)))))
|
||||
|
||||
(defn movie-status [movie & _]
|
||||
(cond
|
||||
(and (:hasFile movie)
|
||||
(:isAvailable movie)
|
||||
(:monitored movie)) :available
|
||||
(and (not (:hasFile movie))
|
||||
(:isAvailable movie)
|
||||
(:monitored movie)) :processing
|
||||
:else nil))
|
||||
9
src/doplarr/specs.clj
Normal file
9
src/doplarr/specs.clj
Normal file
@@ -0,0 +1,9 @@
|
||||
(ns doplarr.specs
|
||||
(:require
|
||||
[clojure.spec.alpha :as spec]))
|
||||
|
||||
(spec/def ::result-name string?)
|
||||
(spec/def ::result-year int?)
|
||||
(spec/def ::result-id int?)
|
||||
|
||||
(spec/def ::search-result (spec/keys :req []))
|
||||
58
src/doplarr/utils.clj
Normal file
58
src/doplarr/utils.clj
Normal file
@@ -0,0 +1,58 @@
|
||||
(ns doplarr.utils
|
||||
(:require
|
||||
[clojure.tools.logging :as log]
|
||||
[camel-snake-kebab.core :as csk]
|
||||
[camel-snake-kebab.extras :as cske]
|
||||
[clojure.core.async :as a]
|
||||
[fmnoise.flow :as flow :refer [then else]]
|
||||
[hato.client :as hc]))
|
||||
|
||||
(defn fatal-error [ex]
|
||||
(log/fatal ex)
|
||||
#_(System/exit -1))
|
||||
|
||||
(defn deep-merge [a & maps]
|
||||
(if (map? a)
|
||||
(apply merge-with deep-merge a maps)
|
||||
(apply merge-with deep-merge maps)))
|
||||
|
||||
(defn http-request [method url key & [params]]
|
||||
(let [chan (a/chan)
|
||||
put-close #(do
|
||||
(a/put! chan %)
|
||||
(a/close! chan))]
|
||||
(hc/request
|
||||
(deep-merge
|
||||
{:method method
|
||||
:url url
|
||||
:as :json-string-keys
|
||||
:coerce :always
|
||||
:async? true
|
||||
:headers {"X-API-Key" key}}
|
||||
params)
|
||||
put-close
|
||||
put-close)
|
||||
chan))
|
||||
|
||||
(defn from-camel [m]
|
||||
(cske/transform-keys csk/->kebab-case-keyword m))
|
||||
|
||||
(defn to-camel [m]
|
||||
(cske/transform-keys csk/->camelCaseString m))
|
||||
|
||||
(defn process-search-result [result]
|
||||
(-> result
|
||||
(select-keys ["title" "year" "id" "tvdbId" "tmdbId"])
|
||||
from-camel))
|
||||
|
||||
(defn process-quality-profile [profile]
|
||||
(->> (select-keys profile ["id" "name"])
|
||||
from-camel))
|
||||
|
||||
(defn request-and-process-body [request-fn process-fn & request-args]
|
||||
(a/go
|
||||
(->> (a/<! (apply request-fn request-args))
|
||||
(then #(process-fn (:body %)))
|
||||
(else #(fatal-error (ex-info (str "Error on request from " request-fn)
|
||||
{:args request-args
|
||||
:exception (ex-data %)}))))))
|
||||
Reference in New Issue
Block a user