#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)))))