infod 0.0.2 → 0.0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/infod.rb +51 -12
- data/infod/{Th/404.rb → 404.rb} +4 -16
- data/infod/500.rb +53 -0
- data/infod/GET.rb +104 -0
- data/infod/HEAD.rb +23 -0
- data/infod/HTTP.rb +105 -0
- data/infod/{Th/PATCH.rb → PATCH.rb} +0 -0
- data/infod/POST.rb +34 -0
- data/infod/audio.rb +30 -0
- data/infod/blog.rb +34 -0
- data/infod/cal.rb +72 -0
- data/infod/{Es/code.rb → code.rb} +7 -4
- data/infod/constants.rb +55 -0
- data/infod/{Es/css.rb → css.rb} +0 -0
- data/infod/{Es/csv.rb → csv.rb} +0 -0
- data/infod/{Es/du.rb → du.rb} +0 -0
- data/infod/edit.rb +73 -0
- data/infod/{H/facets.rb → facets.rb} +20 -11
- data/infod/{Es/feed.rb → feed.rb} +17 -16
- data/infod/{Es/find.rb → find.rb} +2 -3
- data/infod/forum.rb +13 -0
- data/infod/{Es/fs.rb → fs.rb} +5 -2
- data/infod/glob.rb +26 -0
- data/infod/graph.rb +131 -0
- data/infod/{Es/grep.rb → grep.rb} +3 -3
- data/infod/{Es/groonga.rb → groonga.rb} +35 -26
- data/infod/{H/histogram.rb → histogram.rb} +23 -16
- data/infod/html.rb +231 -0
- data/infod/{Es/image.rb → image.rb} +16 -26
- data/infod/{Es/index.rb → index.rb} +44 -49
- data/infod/infod.rb +51 -12
- data/infod/json.rb +38 -0
- data/infod/{Es/kv.rb → kv.rb} +3 -9
- data/infod/{Y.rb → lambda.rb} +18 -1
- data/infod/ls.rb +49 -0
- data/infod/mail.rb +108 -0
- data/infod/{Es/man.rb → man.rb} +3 -15
- data/infod/{H/microblog.rb → microblog.rb} +22 -31
- data/infod/{K.rb → mime.rb} +68 -52
- data/infod/{N.rb → names.rb} +77 -56
- data/infod/page.rb +13 -0
- data/infod/postscript.rb +26 -0
- data/infod/rdf.rb +51 -0
- data/infod/{Rb.rb → ruby.rb} +18 -33
- data/infod/{Es/schema.rb → schema.rb} +23 -8
- data/infod/{Es/search.rb → search.rb} +5 -11
- data/infod/{Es/sh.rb → sh.rb} +0 -0
- data/infod/{Es/text.rb → text.rb} +33 -29
- data/infod/{H/threads.rb → threads.rb} +20 -27
- data/infod/{H/time.rb → time.rb} +14 -34
- data/infod/{H/wiki.rb → wiki.rb} +0 -0
- metadata +53 -64
- data/config.ru +0 -3
- data/infod/Es.rb +0 -31
- data/infod/Es/filter.rb +0 -75
- data/infod/Es/glob.rb +0 -22
- data/infod/Es/html.rb +0 -271
- data/infod/Es/in.rb +0 -68
- data/infod/Es/json.rb +0 -68
- data/infod/Es/ls.rb +0 -58
- data/infod/Es/mail.rb +0 -87
- data/infod/Es/mime.rb +0 -59
- data/infod/Es/out.rb +0 -52
- data/infod/Es/pager.rb +0 -34
- data/infod/Es/pdf.rb +0 -19
- data/infod/Es/rdf.rb +0 -35
- data/infod/H.rb +0 -15
- data/infod/H/audio.rb +0 -19
- data/infod/H/blog.rb +0 -15
- data/infod/H/cal.rb +0 -81
- data/infod/H/edit.rb +0 -88
- data/infod/H/forum.rb +0 -4
- data/infod/H/hf.rb +0 -114
- data/infod/H/mail.rb +0 -92
- data/infod/H/who.rb +0 -30
- data/infod/Th.rb +0 -36
- data/infod/Th/500.rb +0 -41
- data/infod/Th/GET.rb +0 -62
- data/infod/Th/HEAD.rb +0 -5
- data/infod/Th/POST.rb +0 -39
- data/infod/Th/perf.rb +0 -37
- data/infod/Th/uid.rb +0 -24
- data/infod/Th/util.rb +0 -89
data/infod.rb
CHANGED
@@ -1,12 +1,51 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
%w{
|
2
|
+
constants
|
3
|
+
lambda
|
4
|
+
mime
|
5
|
+
404
|
6
|
+
500
|
7
|
+
audio
|
8
|
+
blog
|
9
|
+
cal
|
10
|
+
code
|
11
|
+
css
|
12
|
+
csv
|
13
|
+
du
|
14
|
+
edit
|
15
|
+
facets
|
16
|
+
feed
|
17
|
+
find
|
18
|
+
forum
|
19
|
+
fs
|
20
|
+
GET
|
21
|
+
glob
|
22
|
+
graph
|
23
|
+
grep
|
24
|
+
groonga
|
25
|
+
HEAD
|
26
|
+
histogram
|
27
|
+
html
|
28
|
+
HTTP
|
29
|
+
image
|
30
|
+
index
|
31
|
+
json
|
32
|
+
kv
|
33
|
+
ls
|
34
|
+
mail
|
35
|
+
man
|
36
|
+
microblog
|
37
|
+
names
|
38
|
+
page
|
39
|
+
PATCH
|
40
|
+
POST
|
41
|
+
postscript
|
42
|
+
rdf
|
43
|
+
ruby
|
44
|
+
schema
|
45
|
+
search
|
46
|
+
sh
|
47
|
+
text
|
48
|
+
threads
|
49
|
+
time
|
50
|
+
wiki
|
51
|
+
}.map{|e|require_relative e}
|
data/infod/{Th/404.rb → 404.rb}
RENAMED
@@ -1,4 +1,3 @@
|
|
1
|
-
watch __FILE__
|
2
1
|
class E
|
3
2
|
|
4
3
|
E404 = 'req/'+HTTP+'404'
|
@@ -16,8 +15,8 @@ r.map{|k,v| s[Header + k] = k == 'uri' ? v : [v] }
|
|
16
15
|
s[Header+'ACCEPT'] = [r.accept]
|
17
16
|
s[Type] = [E[HTTP+'Response']]
|
18
17
|
s[HTTP+'statusCodeValue'] = [404]
|
19
|
-
s[Header+'HTTP_HOST'] = [E['http://' + s[Header+'HTTP_HOST'][0]]]
|
20
|
-
s[Edit] = [E[r['REQUEST_PATH']+'?
|
18
|
+
s[Header+'HTTP_HOST'] = [E['http://' + s[Header+'HTTP_HOST'][0]]] if s[Header+'HTTP_HOST']
|
19
|
+
s[Edit] = [E[r['REQUEST_PATH']+'?graph=edit']]
|
21
20
|
s['#query'] = [r.q]
|
22
21
|
s['#seeAlso'] = [e.parent,*e.a('*').glob]
|
23
22
|
r.q['view'] = '404'
|
@@ -28,21 +27,10 @@ s[HTTP+'statusCodeValue'] = [404]
|
|
28
27
|
[H.css('/css/404'),{_: :style, c: "a {background-color:#{E.cs}}"},
|
29
28
|
d.html]}
|
30
29
|
|
31
|
-
# a
|
30
|
+
# a placeholder graph
|
31
|
+
# useful for initializing an editor on an empty resource
|
32
32
|
fn 'protograph/_',->d,_,m{
|
33
33
|
m[d.uri] = {}
|
34
34
|
rand.to_s.h}
|
35
35
|
|
36
|
-
# check response-codes for a list of URIs (linebreak-separated *.u files)
|
37
|
-
def checkURIs
|
38
|
-
r = uris.select{|u|u.to_s.match /^http/}.map{|u|
|
39
|
-
c = [`curl -IsA 404? "#{u}"`.lines.to_a[0].match(/\d{3}/)[0].to_i,u] # HEAD
|
40
|
-
puts c.join ' '
|
41
|
-
c } # status, uri tuple
|
42
|
-
puts "\n\n"
|
43
|
-
r.map{|c|
|
44
|
-
# show anomalies
|
45
|
-
puts c.join(' ') unless c[0] == 200 }
|
46
|
-
end
|
47
|
-
|
48
36
|
end
|
data/infod/500.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#watch __FILE__
|
2
|
+
class E
|
3
|
+
|
4
|
+
Errors ||= {}
|
5
|
+
|
6
|
+
fn 'E500',->x,e{
|
7
|
+
stack = x.backtrace
|
8
|
+
$stderr.puts [500, e['REQUEST_URI'], x.class, x.message, stack[0]].join ' '
|
9
|
+
|
10
|
+
Errors[e['uri']] ||= {}
|
11
|
+
Errors[e['uri']][:time] = Time.now
|
12
|
+
Errors[e['uri']][:env] = [e, x.class.to_s, x.message, stack.join('<br>')]
|
13
|
+
|
14
|
+
[500,{'Content-Type'=>'text/html'},
|
15
|
+
[H[{_: :html,
|
16
|
+
c: [{_: :head,
|
17
|
+
c: [{_: :title, c: 500},(H.css '/css/500')]},
|
18
|
+
{_: :body,
|
19
|
+
c: [{_: :h1, c: 500},
|
20
|
+
{_: :table,
|
21
|
+
c: [{_: :tr,c: [{_: :td, c: {_: :b, c: x.class}},{_: :td, class: :space},{_: :td, class: :message, c: x.message.hrefs}]},
|
22
|
+
stack.map{|f| p = f.split /:/, 3
|
23
|
+
{_: :tr,
|
24
|
+
c: [{_: :td, class: :path, c: p[0].abbrURI},
|
25
|
+
{_: :td, class: :index, c: p[1]},
|
26
|
+
{_: :td, class: :context, c: (p[2]||'').hrefs}].cr}}.cr]}]}]}]]]}
|
27
|
+
|
28
|
+
F['/500/GET'] = ->e,r{H([Errors.sort_by{|u,r|r[:time]}.reverse.html,H.css('/css/500')]).hR}
|
29
|
+
F['/500/test/GET'] = ->e,r{1/0}
|
30
|
+
|
31
|
+
F['view/'+COGS+'Exception']=->e,r{
|
32
|
+
e.values.map{|e|
|
33
|
+
{style: 'border-radius:1em;background-color:#333;color:#eee;float:left;max-width:42em',
|
34
|
+
c: [{_: :h2, c: "<b style='background-color:#f00'>¿</b>"+(e[Title]||[]).to_s},
|
35
|
+
e[Content]||''
|
36
|
+
]}}}
|
37
|
+
|
38
|
+
# filesystem takes priority over this if it's found
|
39
|
+
fn '/css/500.css/GET',->e,r{
|
40
|
+
[200,{'Content-Type'=>'text/css'},["
|
41
|
+
body {margin:0; font-family: sans-serif; background-color:#fff; color:#000}
|
42
|
+
h1 {padding:.2em; background-color:#f00; color:#fff; margin:0}
|
43
|
+
div {display:inline}
|
44
|
+
table {border-spacing:0;margin:0}
|
45
|
+
b {background-color:#eee;color:#500;padding:.1em .3em .1em .3em}
|
46
|
+
.frag {font-weight:bold; color:#000; background-color:#{E.cs}}
|
47
|
+
td.space {background-color:#ddd}
|
48
|
+
td.message {background-color:#009;color:#fff}
|
49
|
+
td.path {text-align:right}
|
50
|
+
td.index {text-align:right;border-color:#000;border-width:0 0 .1em 0;border-style:dotted;background-color:#ddd;color:#000}
|
51
|
+
td.context {border-color:#ddd;border-width:0 0 .1em 0;border-style:dotted;padding:.15em}"]]}
|
52
|
+
|
53
|
+
end
|
data/infod/GET.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
class E
|
2
|
+
|
3
|
+
Apache = ENV['apache']
|
4
|
+
Nginx = ENV['nginx']
|
5
|
+
|
6
|
+
def GET
|
7
|
+
if reqFn = @r.q['y'].do{|r| F['req/'+r] }
|
8
|
+
# bespoke handler
|
9
|
+
reqFn[self,@r]
|
10
|
+
|
11
|
+
elsif file = [self,pathSegment].compact.find(&:f)
|
12
|
+
|
13
|
+
# file exists, but client might not accept its MIME, or want it transformed to another MIME
|
14
|
+
a = @r.accept.values.flatten
|
15
|
+
accepted = a.empty? || (a.member? file.mimeP) || (a.member? '*/*')
|
16
|
+
(!accepted || MIMEcook[file.mimeP] || @r.q.has_key?('view')) ?
|
17
|
+
resource : (file.env @r).getFile
|
18
|
+
|
19
|
+
else
|
20
|
+
resource
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def getFile
|
25
|
+
@r['ETag'] = [m,size].h
|
26
|
+
maybeSend mimeP,->{self},:link
|
27
|
+
end
|
28
|
+
|
29
|
+
def resource
|
30
|
+
# bubble up site then global tree until handled (false return-value to pass)
|
31
|
+
pathSegment.do{|path|
|
32
|
+
lambdas = path.cascade.map{|p| p.uri.t + 'GET' }
|
33
|
+
['http://'+@r['SERVER_NAME'],""].map{|h| lambdas.map{|p|
|
34
|
+
F[h + p].do{|fn| fn[self,@r].do{|r|
|
35
|
+
$stdout.puts [r[0],'http://'+@r['SERVER_NAME']+@r['REQUEST_URI'],@r['HTTP_USER_AGENT'],@r['HTTP_REFERER'],@r.format].join ' '
|
36
|
+
return r
|
37
|
+
}}}}}
|
38
|
+
response
|
39
|
+
end
|
40
|
+
|
41
|
+
def response
|
42
|
+
|
43
|
+
m = {}
|
44
|
+
|
45
|
+
# graph identity (model)
|
46
|
+
g = @r.q['graph']
|
47
|
+
graphID = (g && F['protograph/' + g] || F['protograph/'])[self,@r.q,m]
|
48
|
+
|
49
|
+
return F[E404][self,@r] if m.empty?
|
50
|
+
|
51
|
+
# response identity (view)
|
52
|
+
@r['ETag'] ||= [@r.q['view'].do{|v|F['view/' + v] && v}, graphID, @r.format, Watch].h
|
53
|
+
|
54
|
+
maybeSend @r.format, ->{
|
55
|
+
|
56
|
+
# response
|
57
|
+
r = E'/E/req/' + @r['ETag'].dive
|
58
|
+
if r.e # exists
|
59
|
+
r
|
60
|
+
else
|
61
|
+
|
62
|
+
# graph
|
63
|
+
c = E '/E/graph/' + graphID.dive
|
64
|
+
if c.e # exists
|
65
|
+
m = c.r true
|
66
|
+
else
|
67
|
+
# construct
|
68
|
+
(g && F['graph/' + g] || F['graph/'])[self, @r.q,m]
|
69
|
+
# cache
|
70
|
+
c.w m,true
|
71
|
+
end
|
72
|
+
# cache < construct
|
73
|
+
r.w render @r.format, m, @r
|
74
|
+
end }
|
75
|
+
end
|
76
|
+
|
77
|
+
def send?
|
78
|
+
!((m=@r['HTTP_IF_NONE_MATCH']) && m.strip.split(/\s*,\s*/).include?(@r['ETag']))
|
79
|
+
end
|
80
|
+
|
81
|
+
def maybeSend m, b, iR = false; c = 200
|
82
|
+
send? ? # does agent have this version?
|
83
|
+
b[].do{|b| # continue with response
|
84
|
+
|
85
|
+
h = {'Content-Type'=> m,
|
86
|
+
'ETag'=> @r['ETag']}
|
87
|
+
|
88
|
+
h.update({'Cache-Control' => 'no-transform'}) if m.match /^(audio|image|video)/ # already compresed
|
89
|
+
h.update({'Link' => '<' + @r['uri'] + '?view>; rel=meta'}) if iR # link to description
|
90
|
+
# h.update({'MS-Author-Via' => 'SPARQL'}) # authoring preference
|
91
|
+
|
92
|
+
# frontend-specific response handlers
|
93
|
+
b.class == E ? (Nginx ? # nginx chosen?
|
94
|
+
[c,h.update({'X-Accel-Redirect' => '/fs' + b.path}),[]] : # Nginx handler
|
95
|
+
Apache ? # Apache chosen?
|
96
|
+
[c,h.update({'X-Sendfile' => b.d}),[]] : # Apache handler
|
97
|
+
(r = Rack::File.new nil # Rack handler
|
98
|
+
r.instance_variable_set '@path',b.d # configure Rack response
|
99
|
+
r.serving(@r).do{|s,m,b|[(s == 200 ? c : s),m.update(h),b]})) :
|
100
|
+
[c, h, b]} : # normal response
|
101
|
+
[304,{},[]] # client has response
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
data/infod/HEAD.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
class E
|
2
|
+
|
3
|
+
def HEAD
|
4
|
+
self.GET.do{|s,h,b|[s,h,[]]}
|
5
|
+
end
|
6
|
+
|
7
|
+
def OPTIONS
|
8
|
+
[200,{},[]]
|
9
|
+
end
|
10
|
+
|
11
|
+
# HEAD response-codes on a (.u) list of URIs
|
12
|
+
def checkURIs
|
13
|
+
r = uris.select{|u|u.to_s.match /^http/}.map{|u|
|
14
|
+
c = [`curl -IsA 404? "#{u}"`.lines.to_a[0].match(/\d{3}/)[0].to_i,u] # HEAD
|
15
|
+
puts c.join ' '
|
16
|
+
c } # status, uri tuple
|
17
|
+
puts "\n\n"
|
18
|
+
r.map{|c|
|
19
|
+
# show anomalies
|
20
|
+
puts c.join(' ') unless c[0] == 200 }
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/infod/HTTP.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
#watch __FILE__
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
class E
|
5
|
+
|
6
|
+
def E.call e
|
7
|
+
dev
|
8
|
+
e.extend Th
|
9
|
+
e['HTTP_X_FORWARDED_HOST'].do{|h| e['SERVER_NAME'] = h }
|
10
|
+
p = e['REQUEST_PATH'].force_encoding 'UTF-8'
|
11
|
+
|
12
|
+
uri = CGI.unescape((p.index(URIURL) == 0) ? p[URIURL.size..-1] : ('http://'+e['SERVER_NAME']+(p.gsub '+','%2B'))).E.env e
|
13
|
+
|
14
|
+
uri.inside ? ( e['uri'] = uri.uri
|
15
|
+
uri.send e.verb ) : [403,{},[]]
|
16
|
+
|
17
|
+
rescue Exception => x
|
18
|
+
F['E500'][x,e]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class String
|
24
|
+
|
25
|
+
# querystring parse
|
26
|
+
def qp
|
27
|
+
d={}
|
28
|
+
split(/&/).map{|e|
|
29
|
+
k,v=e.split(/=/,2).map{|x|
|
30
|
+
CGI.unescape x}
|
31
|
+
d[k]=v}
|
32
|
+
d
|
33
|
+
end
|
34
|
+
|
35
|
+
def hR
|
36
|
+
[200, {'Content-Type'=>'text/html; charset=utf-8'}, [self]]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
module Th
|
42
|
+
|
43
|
+
# query-string
|
44
|
+
def qs
|
45
|
+
(['GET','HEAD'].member? verb) ? self['QUERY_STRING'] : self['rack.input'].read
|
46
|
+
end
|
47
|
+
|
48
|
+
# parsed query-string
|
49
|
+
def q
|
50
|
+
@q ||= (qs||'').qp
|
51
|
+
end
|
52
|
+
|
53
|
+
# Accept header -> Hash
|
54
|
+
def accept_ k=''
|
55
|
+
d={}
|
56
|
+
self['HTTP_ACCEPT'+k].do{|k|
|
57
|
+
(k.split /,/).map{|e| # each pair
|
58
|
+
f,q = e.split /;/ # split MIME from q value
|
59
|
+
i = q && q.split(/=/)[1].to_f || 1.0
|
60
|
+
d[i] ||= []; d[i].push f.strip}} # append
|
61
|
+
d
|
62
|
+
end
|
63
|
+
|
64
|
+
def format
|
65
|
+
@format ||= conneg
|
66
|
+
end
|
67
|
+
|
68
|
+
def conneg
|
69
|
+
# extension
|
70
|
+
{ '.html' => 'text/html',
|
71
|
+
'.jsonld' => 'application/ld+json',
|
72
|
+
'.nt' => 'text/ntriples',
|
73
|
+
'.n3' => 'text/n3',
|
74
|
+
'.ttl' => 'text/turtle',
|
75
|
+
}[File.extname self['uri']].do{|mime|
|
76
|
+
return mime}
|
77
|
+
|
78
|
+
# Accept header
|
79
|
+
accept.sort.reverse.map{|q,mimes|
|
80
|
+
mimes.map{|mime|
|
81
|
+
return mime if E::F[E::Render+mime]}}
|
82
|
+
'text/html'
|
83
|
+
end
|
84
|
+
|
85
|
+
def accept; @accept ||= accept_ end
|
86
|
+
|
87
|
+
def verb
|
88
|
+
self['REQUEST_METHOD']
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
class Hash
|
94
|
+
|
95
|
+
# unparse querystring
|
96
|
+
def qs
|
97
|
+
'?'+map{|k,v|k.to_s+'='+(v ? (CGI.escape [*v][0].to_s) : '')}.intersperse("&").join('')
|
98
|
+
end
|
99
|
+
|
100
|
+
def env
|
101
|
+
@r = r
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
File without changes
|
data/infod/POST.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#watch __FILE__
|
2
|
+
class E
|
3
|
+
|
4
|
+
def POST
|
5
|
+
type = @r['CONTENT_TYPE']
|
6
|
+
case type
|
7
|
+
when /^application\/sparql-update/
|
8
|
+
|
9
|
+
when /^application\/x-www-form-urlencoded/
|
10
|
+
ch = nil
|
11
|
+
(Rack::Request.new @r).params.map{|k,v|
|
12
|
+
s, p, o = (CGI.unescape k).split S
|
13
|
+
if s && p && o
|
14
|
+
oP = o
|
15
|
+
s, p, o = [s, p, o].map &:unpath
|
16
|
+
s = s.uri[0..-2].E if s.uri[-1] == '/'
|
17
|
+
p = p.uri[0..-2].E if p.uri[-1] == '/'
|
18
|
+
if oP.E == (E.literal v) && s.uri.match(/^http/) && p.uri.match(/^http/)
|
19
|
+
puts "POST <#{s}> <#{p}> <#{o}>"
|
20
|
+
s[p,o,v]
|
21
|
+
ch = true
|
22
|
+
end
|
23
|
+
end}
|
24
|
+
if ch # state changed
|
25
|
+
g = {}
|
26
|
+
fromStream g, :triplrFsStore
|
27
|
+
ef.w g, true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
[303,{'Location'=>uri},[]]
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/infod/audio.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
class E
|
2
|
+
|
3
|
+
VideoFile = /(avi|flv|mkv|mpg|mp4|wmv)$/i
|
4
|
+
AudioFile = /(aif|wav|flac|mp3|m4a|aac|ogg)$/i
|
5
|
+
|
6
|
+
fn 'set/audio',->d,e,m{d.take.select{|e|e.ext.match AudioFile}}
|
7
|
+
fn 'set/video',->d,e,m{d.take.select{|e|e.ext.match VideoFile}}
|
8
|
+
|
9
|
+
AudioK = {}
|
10
|
+
%w{Album-Movie-Show_title Lead_performers-Soloists Title-songname-content_description}.
|
11
|
+
map{|a|Audio + a}.concat(['uri', Stat+'mtime', Stat+'size']).map{|p|AudioK[p] = true}
|
12
|
+
|
13
|
+
fn 'view/audio',->d,e{ d = d.dup
|
14
|
+
|
15
|
+
# skip non-audio files
|
16
|
+
d.delete_if{|p,o|
|
17
|
+
(p.respond_to? :match) &&
|
18
|
+
(!p.match AudioFile)}
|
19
|
+
|
20
|
+
# select data-fields
|
21
|
+
d.values.map{|r|
|
22
|
+
r.class==Hash &&
|
23
|
+
r.delete_if{|p,o|!AudioK[p]}}
|
24
|
+
|
25
|
+
[(H.once e, :mu, (H.js '/js/mu')),(H.once e, :audio,(H.js '/js/audio'),(H.css '/css/audio'),
|
26
|
+
{id: :rand, c: :r}, {id: :jump, c: '→'}, {id: :info, target: :_blank, _: :a},
|
27
|
+
{_: e.q.has_key?('video') ? :video : :audio, id: :media, controls: true}), '<br>',
|
28
|
+
F['view/table'][d,e]]}
|
29
|
+
|
30
|
+
end
|