aboutsummaryrefslogtreecommitdiff
#lang typed/racket

(require typed/xml)
(require typed/net/url)
(require srfi/2)

(require/typed/provide html
  [read-html-as-xml (-> Input-Port (Listof XML-Content))])

(: get-youtube-rss-url (-> String (Option String)))
(define (get-youtube-rss-url url)
  (define-values (status-line _header in)
    (http-sendrecv/url (string->url url)))
  (cond
    [(and-let* ([code (status-line->code status-line)]
                [(= code 200)])
       (find-channel-id (map xml->xexpr (read-html-as-xml in))))
     => (lambda (channel-id)
          (string-append "https://www.youtube.com/feeds/videos.xml?channel_id=" channel-id))]
    [else #f]))

(: find-channel-id (-> Any (Option String)))
(define (find-channel-id xexpr)
  (match xexpr
    [`(meta ((content ,content) (itemprop "identifier")))
     (and (string? content)
          content)]
    [(list* h t)
     (or (find-channel-id h) (find-channel-id t))]
    [else #f]))

(: status-line->code (-> Bytes (Option Number)))
(define (status-line->code status-line)
  (string->number (second (string-split (bytes->string/utf-8 status-line)))))

(module+ main
  (require racket/cmdline)
  (command-line
   #:program "get-youtube-rss-url"
   #:once-each
   #:args (url)
   (and (string? url)
        (displayln (get-youtube-rss-url url)))))