A script for downloading PeerTube videos
Tags: peertube, download, commonlisp
Published: 2021-07-28 17:19:09

---
title: A script for downloading PeerTube videos
published: true
description: 
tags: peertube, download, commonlisp
//cover_image: https://direct_url_to_image.jpg
---

Since peertube.social is closing down, I need a script for downloading all of my videos. I searched for this for a few minutes. I felt that it exists but I can't find, so I wrote mine in Common Lisp.

It probably works on other Common Lisp implementations too but I only tested on SBCL 2.0.1-5.fc34. 


```Lisp
;; How to run
;; sbcl --load download-peertube-videos.lisp

(ql:quickload :jonathan)
(ql:quickload :dexador)
(ql:quickload :alexandria)
(ql:quickload :asdf)

(import 'alexandria:assoc-value)

(defparameter *username* "peertube-user-name")
(defparameter *hostname* "peertube.social")
(defparameter *get-videos-url* (format nil "https://~A/api/v1/accounts/~A/videos" *hostname* *username*))

(defparameter *videos-info* (assoc-value (jonathan:parse (dex:get *get-videos-url*)
                                                         :as :alist)
                                         "data"
                                         :test 'equal))

(defparameter *total* (assoc-value (jonathan:parse (dex:get (format nil "https://~A/api/v1/accounts/~A/videos" *hostname* *username*))
                                                   :as :alist)
                                   "total"
                                   :test 'equal))

(defparameter *count* 5)

(defun get-video-id (video-info)
  (assoc-value video-info "id" :test 'equal))

(defun get-video-json (video-id)
  (let ((video-info-url (format nil "https://~A/api/v1/videos/~A" *hostname* video-id)))
    (dex:get video-info-url)))

(defun download-video (video-details)
  (let* ((files (assoc-value video-details "files" :test 'equal))
         (download-url (assoc-value (car files) "fileDownloadUrl" :test 'equal))
         (cmd (format nil "wget ~A" download-url)))
    (format t "CMD: ~A~%" cmd)
    (uiop:run-program cmd :output t)))

(defun save-metadata (video-id video-json)
  (with-open-file (f (format nil "~A.json" video-id)
                     :direction :output
                     :if-exists :supersede
                     :if-does-not-exist :create)
    (write-string video-json f)))

(defun download-video-with-metadata (video-info)
  (let* ((video-id (get-video-id video-info))
         (video-json (get-video-json video-id))
         (video-details (jonathan:parse video-json
                                        :as :alist)))
    (save-metadata video-id video-json)
    (download-video video-details)))

(let ((i 0))
  (loop while (< i *total*)
        do
           (let* ((url (format nil "https://~A/api/v1/accounts/~A/videos?start=~A&count=~A" *hostname* *username* i *count*))
                  
                  (videos-json (dex:get url))
                  (videos-alist (jonathan:parse videos-json :as :alist))
                  (videos-info (assoc-value videos-alist "data" :test 'equal)))
             (format t "*** i = ~A~%" i)
             (loop for video-info in videos-info
                   do
                      (download-video-with-metadata video-info)))
           (setq i (+ i *count*))))
```