summaryrefslogtreecommitdiff
path: root/tw/services/media.scm
blob: 6d82765a82aea85c2362ef161964fd449bbf88e1 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
(define-module (tw services media)
  #:use-module (gnu)
  #:use-module (gnu packages video)
  #:use-module (gnu services)
  #:use-module (gnu services configuration)
  #:use-module (gnu services mcron)
  #:use-module (gnu services shepherd)
  #:use-module (guix gexp)
  #:use-module (guix packages)
  #:export (yt-dlp-service-type
            yt-dlp-configuration))

(define (package-or-false? value)
  (or (package? value) (eq? #f value)))
(define (string-or-gexp? value)
  (or (string? value) (gexp? value)))

(define random-hour-every-second-night
  #~(lambda (now)
      (let* ((even-day
              (if (even? (tm:yday (localtime now)))
                  now
                  (next-day-from now)))
             ;; Between 1 and 6 a.m., randomly, but deterministically for each
             ;; day (to avoid runs being skipped in case mcron is restarted).
             (hour-of-day
              (1+ (random 6 (seed->random-state
                             (tm:yday (localtime even-day)))))))
        (next-hour-from even-day (list hour-of-day)))))

(define-configuration/no-serialization yt-dlp-configuration
  (media-directory string "The directory in which to store downloaded media.
The service expects a @code{.yt-dlp} config directory inside this one.")
  (yt-dlp (package-or-false yt-dlp) "The yt-dlp package to use; or
@code{#false} to use the yt-dlp script inside the config directory.")
  (schedule (string-or-gexp random-hour-every-second-night) "The mcron
schedule on which to run the download script.  By default, picks a random hour
between 01:00 and 06:00 every second night.")
  (user (string "root") "The Unix user name to run the script as.")
  (group (string "root") "The Unix group name to run the script as."))

(define (yt-dlp-cronjob config)
  (list
   (let* ((yt-dlp-package (yt-dlp-configuration-yt-dlp config))
          (yt-dlp-executable
           (if yt-dlp-package
               (file-append yt-dlp-package "/bin/yt-dlp")
               (string-append (yt-dlp-configuration-media-directory config)
                              "/.yt-dlp/yt-dlp"))))
     #~(job #$(yt-dlp-configuration-schedule config)
            (lambda ()
              (chdir #$(yt-dlp-configuration-media-directory config))
              ;; `setgid' first while we're still root
              (setgid (group:gid (getgr #$(yt-dlp-configuration-group config))))
              (setuid (passwd:uid (getpw #$(yt-dlp-configuration-user config))))
              (execl #$yt-dlp-executable
                     "yt-dlp" "--ignore-config" "--config-location" ".yt-dlp"))
            ;; Human-readable string for `herd schedule mcron'.
            (format #f "~a --ignore-config --config-location ~a/.yt-dlp"
                    #$yt-dlp-executable   ; this may be a `<file-append>', so #$ it directly
                    #$(yt-dlp-configuration-media-directory config))))))

(define yt-dlp-service-type
  (service-type
   (name 'yt-dlp)
   (extensions
    (list (service-extension mcron-service-type yt-dlp-cronjob)))
   (description
    "Trigger yt-dlp on a schedule to download videos from YouTube.")))