iens

Manager of links to read
git clone https://git.instinctive.eu/iens.git
Log | Files | Refs | README | LICENSE

get-gruiks.scm (5547B)


      1 ; Copyright (c) 2026, Natacha Porté
      2 ;
      3 ; Permission to use, copy, modify, and distribute this software for any
      4 ; purpose with or without fee is hereby granted, provided that the above
      5 ; copyright notice and this permission notice appear in all copies.
      6 ;
      7 ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8 ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9 ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     10 ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11 ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     12 ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     13 ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     14 
     15 (import
     16   (chicken io)
     17   (chicken process-context)
     18   (chicken string)
     19   (chicken time posix)
     20   openssl ; must be above http-client
     21   http-client
     22   intarweb
     23   rss
     24   sql-de-lite
     25   uri-common)
     26 
     27 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     28 ;; Command-Line Processing
     29 
     30 (define db-name
     31   (let ((arg-list (command-line-arguments)))
     32     (if (>= (length arg-list) 1)
     33       (car arg-list)
     34       "iens.sqlite")))
     35 
     36 ;;;;;;;;;;;;;;;;;;;;;;;
     37 ;; Persistent Storage
     38 
     39 (define db
     40   (open-database db-name))
     41 (exec (sql/transient db "PRAGMA foreign_keys = ON;
     42                          PRAGMA busy_timeout = 5000;"))
     43 ; PRAGMA journal_mode = WAL;
     44 ; PRAGMA synchronous = NORMAL;
     45 
     46 (include "common.scm")
     47 
     48 (assert (= 8 (db-version)))
     49 
     50 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     51 ;; Gruik build from sources
     52 
     53 (define (process-gruik source url title comm)
     54   (if (= 0 (query fetch-value
     55                   (sql db "SELECT count(id) FROM gruik
     56                            WHERE section=? AND url=? AND title=?;")
     57                   source url title)
     58            (query fetch-value
     59                   (sql db "SELECT count(id) FROM entry
     60                            WHERE source=? AND url=? AND title=?;")
     61                   source url title))
     62     (exec
     63       (sql db "INSERT INTO gruik(position, notes, ptime,
     64                                  section, url, title, comment_url,
     65                                  mark, ctime, mtime)
     66                VALUES (-1, '', datetime(?1,'unixepoch'),
     67                        ?2, ?3, ?4, ?5,
     68                        ?6, ?1, ?1);")
     69       (query fetch-value
     70              (sql db "SELECT MAX(CAST(strftime('%s', 'now') as INT),
     71                                  (SELECT max(mtime) FROM gruik) + 1);"))
     72       source url title (if comm comm '())
     73       (if (= 0 (query fetch-value
     74                       (sql db "SELECT count(id) FROM gruik WHERE url=?;")
     75                       url)
     76                (query fetch-value
     77                       (sql db "SELECT count(id) FROM entry WHERE url=?;")
     78                       url))
     79           0 -1))
     80     (exec (sql db "UPDATE gruik
     81                    SET mtime=MAX(CAST(strftime('%s', 'now') as INT),
     82                                  (SELECT max(mtime) FROM gruik) + 1)
     83                    WHERE section=? AND url=? AND title=? AND mark<0;")
     84           source url title)))
     85 
     86 (define (process-rss source items)
     87   (unless (null? items)
     88     (let* ((item  (car items))
     89            (attr  (rss:item-attributes item))
     90            (link  (rss:item-link item))
     91            (title (rss:item-title item))
     92            (comm  (alist-ref 'comments attr)))
     93       (process-gruik source link (if title title link) comm)
     94       (process-rss source (cdr items)))))
     95 
     96 (define (get-source parse url last-modified etag)
     97   (let* ((hlm (if (null? last-modified) '()
     98                   `((if-modified-since
     99                       #(,(seconds->local-time last-modified) ())))))
    100          (het (cond ((null? etag) '())
    101                     ((string=? etag "") '())
    102                     ((eqv? (string-ref etag 0) #\S)
    103                       `((if-none-match (strong . ,(substring etag 1)))))
    104                     ((eqv? (string-ref etag 0) #\W)
    105                       `((if-none-match (weak . ,(substring etag 1)))))
    106                     (else '())))
    107          (req (make-request
    108                 uri: (uri-reference url)
    109                 headers: (headers `(,@hlm ,@het)))))
    110     (let-values (((result _ resp) (with-input-from-request req #f parse)))
    111       (let* ((hdr (response-headers resp))
    112              (lm  (header-value 'last-modified hdr))
    113              (et  (header-value 'etag hdr)))
    114         (when (or (not (null? last-modified)) (not (null? etag)) lm et)
    115           (exec (sql db "UPDATE source_rss SET last_modified=?, etag=?
    116                          WHERE url=?;")
    117                 (if lm (local-time->seconds lm) '())
    118                 (if et (string-append
    119                          (cond ((eq? (car et) 'weak) "W")
    120                                ((eq? (car et) 'strong) "S")
    121                                (else "*"))
    122                          (cdr et))
    123                   '())
    124                 url)))
    125       result)))
    126 
    127 (define (process-source name url last-modified etag)
    128   (let* ((rss (get-source rss:read url last-modified etag))
    129          (source (if (string=? name url)
    130                      (begin
    131                        (exec (sql db "UPDATE source_rss SET name=?
    132                                       WHERE name=? AND url=?;")
    133                              (rss:item-title (rss:feed-channel rss))
    134                              name url)
    135                        (rss:item-title (rss:feed-channel rss)))
    136                      name)))
    137     (assert source)
    138     (process-rss source (rss:feed-items rss))))
    139 
    140 ;;;;;;;;;;;;;;;
    141 ;; Actual Run
    142 
    143 (query
    144   (for-each-row* process-source)
    145   (sql db "SELECT name,url,last_modified,etag FROM source_rss;"))