-
Notifications
You must be signed in to change notification settings - Fork 0
/
tumblrand
executable file
·132 lines (115 loc) · 4.41 KB
/
tumblrand
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/local/bin/gosh
(use srfi-13)
(use srfi-19)
(use srfi-43)
(use util.match :only (match-let1))
(use rfc.http :only (http-get))
(use rfc.json)
(use rfc.822 :only (rfc822-parse-date))
(use math.mt-random :only (mt-random-integer <mersenne-twister>))
(use util.list)
(use gauche.parseopt)
;; http://valvallow.tumblr.com/api/read/json?num=1&type=quote
(define (usage)
(print "usage: tumblrand [-i | -t | -j | -h] <id> <type>")
(print " -i | id ex : -i valvallow")
(print " -t | type ex : -t quote")
(print " -j | json")
(print " -h | help")
(exit 0))
;; (param-pairs->string '(start . 410)'(num . 1)'(type . quote))
;; -> "?start=410&num=1&type=quote"
(define (param-pairs->string . param-pairs)
(if (null? param-pairs)
""
(let1 params (map (^e (string-append (x->string (car e))
"="
(x->string (cdr e))))
param-pairs)
(apply string-append "?" (intersperse "&" params)))))
;; (build-uri "/api/read/json" '(start . 410)'(num . 1)'(type . quote))
;; -> "/api/read/json?start=410&num=1&type=quote"
(define (build-uri request-uri . param-pairs)
(string-append request-uri (apply param-pairs->string param-pairs)))
(define (tumble-uri . param-pairs)
(apply build-uri "/api/read/json" param-pairs))
(define (tumble-server id)
(format "~a.tumblr.com" id))
(define (tumble-json server uri)
(let1 str (values-ref (http-get server uri) 2)
(let* ((idx (string-scan str #\{))
(json (substring str idx (- (string-length str) 1))))
(parse-json-string json))))
(define (tumble-total-count server :optional (type ""))
(let1 uri (tumble-uri '(start . 0)'(num . 1)`(type . ,type))
(let1 json (tumble-json server uri)
(cdr (assoc "posts-total" json)))))
(define (random-number total)
(mt-random-integer (make <mersenne-twister> :seed (sys-time)) total))
(define (tumble-random-json id :optional (type ""))
(let1 server (tumble-server id)
(let1 total (tumble-total-count server type)
(tumble-json server
(tumble-uri `(start . ,(random-number total))
'(num . 1)`(type . ,type))))))
(define (format-date date-string)
(receive (year month day-of-month hour minutes
seconds timezone day-of-week)
(rfc822-parse-date date-string)
(format "~a/~2,'0D/~2,'0D ~2,'0D:~2,'0D:~2,'0D"
year month day-of-month hour minutes seconds)))
;; TODO:
;; - define <type> abstruct class
;; - <type> has show-tumble method
;; - <type> has show-tumble-detail abstruct method
;; - show-tumble call show-tumble-details
;; - show-tumble-details implements concrete <type> class
(define (show-tumble json id type)
(let ((posts (vector-ref (assoc-ref json "posts") 0)))
(let ((tumble-url (assoc-ref posts "url"))
(txt (assoc-ref posts #`",|type|-text"))
(date (assoc-ref posts "date")))
(print #`"id : ,(tumble-server id)")
(print #`"url : ,tumble-url")
(print #`"date : ,(format-date date)")
(print #`"type : ,type")
(print (or txt "")))))
(define (walk-json-alist alist :key (key-fun identity)(val-fun identity))
(define (junction x)
(cond ((pair? x)(walk-json-alist x :key-fun key-fun :val-fun val-fun))
((vector? x)(vector-case x))
(else (val-fun x))))
(define (vector-case v)
(vector-map (^ (idx e)
(junction e))
v))
(map (^l (cons (key-fun (car l))
(junction (cdr l))))
alist))
(define (transform-tumble-json alist)
(walk-json-alist
alist
:val-fun (lambda (s)
(if (string? s)
(regexp-replace-all #/\"/ s "\\\\\"")
s))))
(define (main args)
(let-args (cdr args)
((id "i|id=s")
(type "t|type=s")
(json "j|json")
(help "h|help" => usage)
. rest-args)
(let ((id (or id
(and (not (null? rest-args))
(car rest-args))
(read-line)))
(type (or type
(and (not (null? rest-args))
(not (null? (cdr rest-args)))
(cadr rest-args)))))
(let ((response (tumble-random-json id type)))
(if json
(print (construct-json-string
(transform-tumble-json response)))
(show-tumble response id type))))))