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.

113 lines
5.4 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))
(quit-with-message 1 "please provide 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 (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))))