(define-library (planet) (export make-feed feed-id feed-title feed-url entry-author entry-title entry-content-xhtml entry-iso-date entry-us-english-date entry-english-year-and-month planet-refresh-feed planet-all-entries-ever planet-n-newest-entries planet-group-entries-by-date write-html-file) (import (scheme base) (scheme file) (scheme write) (srfi 1) (srfi 13) (srfi 132)) (cond-expand (chicken (import (only (chicken file) create-directory rename-file) (only (http-client) with-input-from-request) (only (sxml-transforms) SXML->HTML) (only (traversal) group-by) (only (atom) content-xhtml entry-author entry-content entry-title entry-updated feed-entries read-atom-feed)))) (begin (define (take-at-most list n) (let loop ((n n) (new-list '()) (list list)) (if (or (null? list) (< n 1)) (reverse new-list) (loop (- n 1) (cons (car list) new-list) (cdr list))))) (define (disp . xs) (for-each display xs) (newline)) (define (edisp . xs) (parameterize ((current-output-port (current-error-port))) (apply disp xs))) (define (writeln x) (write x) (newline)) (define (copy-binary-port input output) (let ((buffer (make-bytevector (* 64 1024) 0))) (let loop () (let ((n-read (read-bytevector! buffer input))) (if (eof-object? n-read) #t (begin (write-bytevector buffer output 0 n-read) (loop))))))) (define (copy-textual-port input output) (define buffer-size (* 64 1024)) (let loop () (let ((chunk (read-string buffer-size input))) (or (eof-object? chunk) (begin (write-string chunk output) (loop)))))) (define (supersede-text-file filename thunk) (let ((new-filename (string-append filename ".new"))) (with-output-to-file new-filename thunk) (rename-file new-filename filename #t))) (define (path-append . paths) (string-join paths "/")) (define english-month-names (vector "January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December")) ;;; (define-record-type feed (make-feed id title url) feed? (id feed-id) (title feed-title) (url feed-url)) (define (feed-cache-file feed cache-directory) (path-append cache-directory (string-append (feed-id feed) ".xml"))) (define (planet-refresh-feed feed cache-directory) (let ((cache-file (feed-cache-file feed cache-directory))) (create-directory cache-directory) (with-input-from-request (feed-url feed) #f (lambda () (supersede-text-file cache-file (lambda () (copy-textual-port (current-input-port) (current-output-port)))))))) (define (read-feed-from-cache feed cache-directory) (let ((cache-file (feed-cache-file feed cache-directory))) (call-with-port (open-binary-input-file cache-file) read-atom-feed))) (define (entry-content-xhtml entry) (content-xhtml (entry-content entry))) (define (entry-rfc3339-digits n entry) (let ((rfc3339 (entry-updated entry))) (if (and rfc3339 (>= (string-length rfc3339) n)) (substring rfc3339 0 n) (error "No date")))) (define (entry-iso-date entry) (entry-rfc3339-digits 10 entry)) (define (entry-iso-month entry) (entry-rfc3339-digits 7 entry)) (define (entry-y-m-d-integers entry) (let* ((yyyy-mm-dd (entry-iso-date entry)) (year (string->number (substring yyyy-mm-dd 0 4))) (month (string->number (substring yyyy-mm-dd 5 7))) (day (string->number (substring yyyy-mm-dd 8 10)))) (values year month day))) (define (entry-us-english-date entry) (let-values (((year month day) (entry-y-m-d-integers entry))) (let ((month-name (vector-ref english-month-names (- month 1)))) (string-append (number->string day) " " month-name " " (number->string year))))) (define (entry-english-year-and-month entry) (let-values (((year month _) (entry-y-m-d-integers entry))) (let ((month-name (vector-ref english-month-names (- month 1)))) (string-append month-name " " (number->string year))))) (define (entry-iso-date") (SXML->HTML sxml) (newline))))))