;;;; downloader.lisp (in-package #:vampire) (defvar *dl-cluster*) (defvar *media-directory*) (defun start-downloader-service (config) (let ((media-dir (merge-pathnames "media/" (static-directory config)))) (ensure-directories-exist media-dir) (setf *dl-cluster* (legion:make-cluster (downloader-threads config) (lambda (job) (funcall job media-dir))))) (legion:start *dl-cluster*)) (defun add-fetch-track-job (url ok err) "URL is a url to some audio track. OK is a function that accepts a TRACK instance. ERR is a function accepting an error condition" (legion:add-job *dl-cluster* (lambda (media-dir) (handler-case (funcall ok (download-media url media-dir)) (error (e) (funcall err e)))))) (defun trackinfo-file (dir name) (merge-pathnames (format nil "~a.info.json" name) dir)) (defun trackmedia-file (dir) (find-if (lambda (path) (not (string-equal "json" (pathname-type path)))) (uiop:directory-files dir))) (defun trackinfo (path) "Returns a trackinfo object - a list whose first member is a path to a file and whose CDR is a PLIST of attributes to pass to (make-instance 'track ...)" (with-plist ((title :|title|) (track-title :|track|) (album :|album|) (codec :|acodec|) (artist :|artist|) (dur :|duration|) (thumbs :|thumbnails|) (source :|webpage_url|)) (jonathan:parse (alexandria:read-file-into-string path)) (with-plist ((url :|url|)) (first thumbs) (list :source source :title (or track-title title) :album album :codec codec :artist artist :duration dur :thumb-url url)))) (defun download-media (url media-dir) "Download media and create a new track from its audio source, moving the raw audio to the media-dir when done." (with-temp-dir (tmpdir) (let* ((tmpname (default-name "media")) (trackinfo-file (trackinfo-file tmpdir tmpname))) (uiop:run-program (format nil "youtube-dl --playlist-end 1 --write-info-json -x -o \"~a/~a.%(ext)s\" '~a'" tmpdir tmpname url)) (let* ((info (trackinfo trackinfo-file)) (downloaded (trackmedia-file tmpdir)) (file (merge-pathnames (format nil "~a.~a" (nuid) (pathname-type downloaded)) media-dir))) (uiop:copy-file downloaded file) (new-track file info)))))