|
@@ -7,6 +7,8 @@
|
|
|
(defvar *deluge-api* "http://localhost:8112/json")
|
|
(defvar *deluge-api* "http://localhost:8112/json")
|
|
|
(defvar *deluge-password* "chads")
|
|
(defvar *deluge-password* "chads")
|
|
|
(defvar *deluge-request-id* 1)
|
|
(defvar *deluge-request-id* 1)
|
|
|
|
|
+(defvar *chad-music-stats-url* "http://localhost:5000/api/stats"))
|
|
|
|
|
+(defvar *chad-music-rescan-url* "http://localhost:5000/api/rescan"))
|
|
|
|
|
|
|
|
(defun jojo-request (url &rest args &key method parameters content headers basic-auth cookie-jar keep-alive use-connection-pool timeout ssl-key-file ssl-cert-file ssl-key-password stream verbose proxy insecure ca-path user-agent (as :plist))
|
|
(defun jojo-request (url &rest args &key method parameters content headers basic-auth cookie-jar keep-alive use-connection-pool timeout ssl-key-file ssl-cert-file ssl-key-password stream verbose proxy insecure ca-path user-agent (as :plist))
|
|
|
(declare (ignore method parameters basic-auth cookie-jar keep-alive use-connection-pool timeout ssl-key-file ssl-cert-file ssl-key-password stream verbose proxy insecure ca-path user-agent))
|
|
(declare (ignore method parameters basic-auth cookie-jar keep-alive use-connection-pool timeout ssl-key-file ssl-cert-file ssl-key-password stream verbose proxy insecure ca-path user-agent))
|
|
@@ -15,7 +17,10 @@
|
|
|
(push (cons :content-type "application/json") headers))
|
|
(push (cons :content-type "application/json") headers))
|
|
|
(remf args :headers)
|
|
(remf args :headers)
|
|
|
(multiple-value-bind (body status headers uri)
|
|
(multiple-value-bind (body status headers uri)
|
|
|
- (apply #'http-request url :headers headers args)
|
|
|
|
|
|
|
+ (handler-bind
|
|
|
|
|
+ ((sb-int:broken-pipe #'(lambda (c) (declare (ignorable c))
|
|
|
|
|
+ (invoke-restart (find-restart 'dexador:retry-request)))))
|
|
|
|
|
+ (apply #'http-request url :headers headers args))
|
|
|
(unless (stringp body)
|
|
(unless (stringp body)
|
|
|
(setf body (trivial-utf-8:utf-8-bytes-to-string body)))
|
|
(setf body (trivial-utf-8:utf-8-bytes-to-string body)))
|
|
|
(values (jojo:parse body :as as) status headers uri)))
|
|
(values (jojo:parse body :as as) status headers uri)))
|
|
@@ -75,7 +80,10 @@
|
|
|
for prio in (getf status :|file_priorities|)
|
|
for prio in (getf status :|file_priorities|)
|
|
|
do (setf (getf file :|prio|) prio
|
|
do (setf (getf file :|prio|) prio
|
|
|
(getf file :|path|) (pathname (raw-pathname (format nil "~A/~A" save-path (getf file :|path|)))))
|
|
(getf file :|path|) (pathname (raw-pathname (format nil "~A/~A" save-path (getf file :|path|)))))
|
|
|
- collect file)))
|
|
|
|
|
|
|
+ collect file)))
|
|
|
|
|
+
|
|
|
|
|
+(defun deluge-add-torrent-magnet (uri &optional options)
|
|
|
|
|
+ (deluge-request "core.add_torrent_magnet" (list uri options)))
|
|
|
|
|
|
|
|
(defun get-non-skipped (files)
|
|
(defun get-non-skipped (files)
|
|
|
(remove 0 files :key (lambda (f) (getf f :|prio|))))
|
|
(remove 0 files :key (lambda (f) (getf f :|prio|))))
|
|
@@ -108,9 +116,9 @@
|
|
|
:wanted-files (length wanted-dirs)
|
|
:wanted-files (length wanted-dirs)
|
|
|
:media-dirs (remove-duplicates wanted-dirs :test #'equal)))))
|
|
:media-dirs (remove-duplicates wanted-dirs :test #'equal)))))
|
|
|
|
|
|
|
|
-(defun get-import-notify (info)
|
|
|
|
|
|
|
+(defun get-import-notify (info action)
|
|
|
(labels ((f (fl) (getf info fl)))
|
|
(labels ((f (fl) (getf info fl)))
|
|
|
- (format nil "[[🎶]] Добавляем *~a*, ~a альбомов с ~a треками. Весит ~a"
|
|
|
|
|
|
|
+ (format nil "[[🎶]] ~a *~a*, ~a альбомов с ~a треками. Весит ~a" action
|
|
|
(f :name) (length (f :media-dirs)) (f :wanted-files) (format-size (f :total-wanted)))))
|
|
(f :name) (length (f :media-dirs)) (f :wanted-files) (format-size (f :total-wanted)))))
|
|
|
|
|
|
|
|
(defun get-root-paths (info)
|
|
(defun get-root-paths (info)
|
|
@@ -157,23 +165,21 @@
|
|
|
(defun process-downloaded (ih &optional dry)
|
|
(defun process-downloaded (ih &optional dry)
|
|
|
(let* ((status (deluge-get-torrent-status ih +deluge-default-status-fields+))
|
|
(let* ((status (deluge-get-torrent-status ih +deluge-default-status-fields+))
|
|
|
(info (get-torrent-info status))
|
|
(info (get-torrent-info status))
|
|
|
- (notify (get-import-notify info))
|
|
|
|
|
|
|
+ (notify (get-import-notify info "Добавляем"))
|
|
|
(paths (get-root-paths info)))
|
|
(paths (get-root-paths info)))
|
|
|
(send-admins notify dry)
|
|
(send-admins notify dry)
|
|
|
(deluge-pause-torrents ih)
|
|
(deluge-pause-torrents ih)
|
|
|
(deluge-delete-skipped ih dry)
|
|
(deluge-delete-skipped ih dry)
|
|
|
(run-import paths dry)
|
|
(run-import paths dry)
|
|
|
|
|
+ (json-request *chad-music-rescan-url* :method :post)
|
|
|
(if dry (format t "Removing torrent ~a" ih)
|
|
(if dry (format t "Removing torrent ~a" ih)
|
|
|
(deluge-remove-torrent ih))))
|
|
(deluge-remove-torrent ih))))
|
|
|
|
|
|
|
|
(defun process-imports ()
|
|
(defun process-imports ()
|
|
|
(loop
|
|
(loop
|
|
|
- (handler-bind
|
|
|
|
|
- ((sb-int:broken-pipe #'(lambda (c) (declare (ignorable c))
|
|
|
|
|
- (invoke-restart (find-restart 'dexador:retry-request))))
|
|
|
|
|
- (error #'(lambda (c) (log:error "Error processing torrent" c))))
|
|
|
|
|
- (loop for (ih . name) in (deluge-get-seeding-torrents)
|
|
|
|
|
- do (process-downloaded ih)))
|
|
|
|
|
|
|
+ (loop for (ih . name) in (deluge-get-seeding-torrents)
|
|
|
|
|
+ do (handler-case (process-downloaded ih)
|
|
|
|
|
+ (error (c) (log:error "Error processing torrent" name c))))
|
|
|
(sleep 1)))
|
|
(sleep 1)))
|
|
|
|
|
|
|
|
(defvar *watcher* nil "Importer thread ")
|
|
(defvar *watcher* nil "Importer thread ")
|
|
@@ -194,20 +200,40 @@
|
|
|
(bot-send-message (if enable "[🎶] Импортим музло" "[🎶] Пусть мешки парятся")))
|
|
(bot-send-message (if enable "[🎶] Импортим музло" "[🎶] Пусть мешки парятся")))
|
|
|
|
|
|
|
|
(defun handle-status ()
|
|
(defun handle-status ()
|
|
|
- (let ((stats (loop
|
|
|
|
|
|
|
+ (let* ((db-stats (when *chad-music-stats-url*
|
|
|
|
|
+ (json-request *chad-music-stats-url*)))
|
|
|
|
|
+ (stats (loop
|
|
|
for (torrent status) on (deluge-get-torrents-status nil '("state" "name" "total_wanted")) by #'cddr
|
|
for (torrent status) on (deluge-get-torrents-status nil '("state" "name" "total_wanted")) by #'cddr
|
|
|
for state = (getf status :|state|)
|
|
for state = (getf status :|state|)
|
|
|
when (equal state "Downloading") counting t into down
|
|
when (equal state "Downloading") counting t into down
|
|
|
when (equal state "Seeding") counting t into seed
|
|
when (equal state "Seeding") counting t into seed
|
|
|
summing (getf status :|total_wanted|) into size
|
|
summing (getf status :|total_wanted|) into size
|
|
|
finally (return (list :down down :seed seed :size size)))))
|
|
finally (return (list :down down :seed seed :size size)))))
|
|
|
- (bot-send-message (format nil "[[🎶]] Осталось скачать ~a, заимпортить ~a торрентов, общий объём ~a" (getf stats :down) (getf stats :seed) (format-size (getf stats :size)))
|
|
|
|
|
|
|
+ (bot-send-message (format nil "[[🎶]] Осталось скачать ~a, заимпортить ~a торрентов, общий объём ~a.~%Сейчас в базе ~a исполнителей с ~a альбомами и ~a треками, общей длительностью ~a"
|
|
|
|
|
+ (getf stats :down) (getf stats :seed) (format-size (getf stats :size))
|
|
|
|
|
+ (agets db-stats "artists")
|
|
|
|
|
+ (agets db-stats "albums")
|
|
|
|
|
+ (agets db-stats "tracks")
|
|
|
|
|
+ (agets db-stats "duration"))
|
|
|
:parse-mode "markdown")))
|
|
:parse-mode "markdown")))
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+(defparameter +magnet-regex+ (ppcre:create-scanner "magnet:\\?\\S+"))
|
|
|
|
|
+(defun handle-add-torrent (magnet)
|
|
|
|
|
+ (let* ((ih (deluge-add-torrent-magnet magnet))
|
|
|
|
|
+ (status (deluge-get-torrent-status ih +deluge-default-status-fields+))
|
|
|
|
|
+ (info (get-torrent-info status))
|
|
|
|
|
+ (notify (get-import-notify info "Качаем")))
|
|
|
|
|
+ (bot-send-message notify)))
|
|
|
|
|
+
|
|
|
(def-message-cmd-handler handle-cmd-music (:music)
|
|
(def-message-cmd-handler handle-cmd-music (:music)
|
|
|
- (cond
|
|
|
|
|
- ((= 1 (length *args*))
|
|
|
|
|
- (handle-set-watch (equal "on" (car *args*))))
|
|
|
|
|
- (:otherwise (handle-status))))
|
|
|
|
|
|
|
+ (with-chat-in-list :music-admins
|
|
|
|
|
+ (let ((arg (car *args*)))
|
|
|
|
|
+ (cond
|
|
|
|
|
+ ((and (= 1 (length *args*)) (member (string-downcase arg) '("on" "off") :test 'equal))
|
|
|
|
|
+ (handle-set-watch (equal "on" arg)))
|
|
|
|
|
+ ((ppcre:scan-to-strings +magnet-regex+ arg)
|
|
|
|
|
+ (handle-add-torrent (ppcre:scan-to-strings +magnet-regex+ arg)))
|
|
|
|
|
+ (:otherwise (handle-status))))))
|
|
|
|
|
|
|
|
(add-hook :starting #'ensure-watcher)
|
|
(add-hook :starting #'ensure-watcher)
|