You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
5.5 KiB
Common Lisp
114 lines
5.5 KiB
Common Lisp
;;;; seanut.lisp
|
|
|
|
(in-package #:seanut)
|
|
|
|
(defun prompt-and-download (domain auth item opts &optional assume-yes)
|
|
"prompt the user with y-or-n-p and download ITEM"
|
|
;; debug print statements lol
|
|
(format t "~A~%" auth)
|
|
(y-or-n-p)
|
|
|
|
|
|
(labels ((generate-root-name (&optional add-trailing)
|
|
(format nil "~A (~A)~@[ Season ~A~]~@[/~]"
|
|
(gethash "Name" item)
|
|
(gethash "ProductionYear" item)
|
|
(getf opts :season-number)
|
|
add-trailing))
|
|
|
|
(ensure-download-dir (&optional new-path)
|
|
(ensure-directories-exist
|
|
(merge-pathnames (or new-path "")
|
|
(merge-pathnames (generate-root-name 'add-slash)
|
|
(getf opts :output #P"./")))))
|
|
|
|
(download-item-or-children (item &optional parents)
|
|
;; PARENTS is a list of all parent names with FIRST being
|
|
;; the oldest grandparent (for building complete download path)
|
|
(let ((children (if (string= (gethash "Type" item) "Season")
|
|
(json-request (format-url domain "Shows/~A/Episodes?fields=Path~@[&season=~A~]"
|
|
(gethash "Id" item)
|
|
(getf opts :season-number))
|
|
auth)
|
|
(json-request (format-url domain "Items?fields=Path&parentId=~A"
|
|
(gethash "Id" item))
|
|
auth))))
|
|
(if (zerop (length children))
|
|
;; download single file
|
|
;; to get the extension type i think we may need to include
|
|
;; "Path" field in the api request, then use that to get the extension
|
|
(download-media (format nil "~A~A~{~A~^/~}~A.~A"
|
|
(getf opts :output #P"./")
|
|
(generate-root-name 'trailing)
|
|
parents (gethash "Name" item)
|
|
(pathname-type (gethash "Path" item)))
|
|
(format-url domain "Items/~A/Download"
|
|
(gethash "Id" item))
|
|
auth)
|
|
|
|
;; if the item has children we need to download them.
|
|
;; to accomplish this we get the list of children
|
|
;; and loop over them, recursing for each one
|
|
;; ensure that a directory exists for Parent
|
|
;; then recurse with children
|
|
(progn
|
|
(ensure-download-dir (format nil "~A~A~{~A/~}~A"
|
|
(getf opts :output #P"./")
|
|
(generate-root-name 'trailing)
|
|
parents (gethash "Name" item)))
|
|
(loop :for child :in children
|
|
:do (apply #'download-item-or-children
|
|
`(,child (,@parents ,(gethash "Name" item))))))))))
|
|
(when (or assume-yes
|
|
(y-or-n-p "Download ~A" (generate-root-name)))
|
|
(ensure-download-dir)
|
|
(download-item-or-children item))))
|
|
|
|
|
|
(defun main ()
|
|
"binary entry point"
|
|
(handle-user-abort
|
|
(multiple-value-bind (opts args) (get-opts)
|
|
(when (or (getf opts :help)
|
|
(and (every #'null args)
|
|
(every #'null opts)))
|
|
(opts:describe :usage-of "seanut"
|
|
:args "DOMAIN MEDIA-NAME")
|
|
(uiop:quit 0))
|
|
|
|
(when (getf opts :version)
|
|
(quit-with-message 0 "seanut v~A" (seanut-version)))
|
|
|
|
(unless (or (and (getf opts :username)
|
|
(getf opts :password))
|
|
(getf opts :quick-connect-p)
|
|
(getf opts :token))
|
|
(quit-with-message 1 "please provide an access token, username & password, or use quick connect"))
|
|
|
|
(unless (getf opts :media-type)
|
|
(quit-with-message 1 "Please specify media type to download.~%~A ~{~A~^, ~}"
|
|
"Supported media types are:"
|
|
*valid-media-types*))
|
|
|
|
(when (some #'null args)
|
|
(quit-with-message 1 "domain and/or media name not provided"))
|
|
|
|
(destructuring-bind (domain search-term) args
|
|
(let* ((authorization (or (getf opts :token)
|
|
(generate-authorization (get-access-token domain opts))))
|
|
(results (run-search-query domain authorization
|
|
(getf opts :media-type)
|
|
(url-encode search-term))))
|
|
(if (< 0 (length results))
|
|
;; FIXME: for some reason this access token is not "valid" enough to get
|
|
;; certain info? when we run the parentID search it craps out on us?
|
|
;; maybe its not something wrong with the token, but the auth string as a
|
|
;; whole? look into this more tomorrow
|
|
(loop :for item :across results
|
|
:do (prompt-and-download domain authorization
|
|
item (getf opts :assume-yes)))
|
|
(quit-with-message 0 "No results found for ~A" search-term)))))
|
|
|
|
(error (e)
|
|
(quit-with-message 1 "encountered error: ~A" e))))
|