murlsh 0.11.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.htaccess +2 -0
- data/README.textile +3 -33
- data/Rakefile +12 -5
- data/VERSION +1 -1
- data/config.ru +10 -4
- data/config.yaml +6 -12
- data/lib/murlsh/dispatch.rb +0 -6
- data/lib/murlsh/img_store.rb +36 -0
- data/lib/murlsh/markup.rb +0 -1
- data/lib/murlsh/plugin.rb +2 -6
- data/lib/murlsh/uri_ask.rb +66 -22
- data/lib/murlsh/url.rb +0 -18
- data/lib/murlsh/url_body.rb +15 -23
- data/lib/murlsh/url_server.rb +5 -5
- data/murlsh.gemspec +44 -19
- data/plugins/add_post_50_update_feed.rb +17 -3
- data/plugins/add_post_50_update_podcast.rb +46 -0
- data/plugins/add_post_50_update_rss.rb +18 -2
- data/plugins/add_post_60_notify_hubs.rb +3 -1
- data/plugins/add_pre_40_convert_mobile.rb +30 -0
- data/plugins/add_pre_50_lookup_content_type_title.rb +11 -4
- data/plugins/add_pre_60_flickr.rb +38 -0
- data/plugins/add_pre_60_github_title.rb +5 -1
- data/plugins/add_pre_60_google_code_title.rb +5 -2
- data/plugins/add_pre_60_imageshack.rb +31 -0
- data/plugins/add_pre_60_imgur.rb +32 -0
- data/plugins/add_pre_60_s3_image.rb +34 -0
- data/plugins/add_pre_60_twitter.rb +35 -0
- data/plugins/add_pre_60_vimeo.rb +35 -0
- data/plugins/add_pre_60_youtube.rb +31 -0
- data/plugins/html_parse_50_hpricot.rb +2 -0
- data/plugins/url_display_add_45_mp3.rb +30 -0
- data/plugins/url_display_add_50_hostrec.rb +38 -0
- data/plugins/url_display_add_55_content_type.rb +27 -0
- data/plugins/url_display_add_60_via.rb +52 -0
- data/plugins/url_display_add_65_time.rb +22 -0
- data/public/css/jquery.jgrowl.css +0 -3
- data/public/css/screen.css +0 -18
- data/public/img/thumb/README +0 -0
- data/public/js/jquery-1.4.3.min.js +166 -0
- data/public/js/js.js +62 -234
- data/public/js/twitter-text-1.0.3.js +538 -0
- data/spec/img_store_spec.rb +53 -0
- data/spec/uri_ask_spec.rb +14 -4
- metadata +139 -37
- data/lib/murlsh/flickr_server.rb +0 -55
- data/lib/murlsh/twitter_server.rb +0 -45
- data/lib/murlsh/unwrap_jsonp.rb +0 -15
- data/lib/murlsh/xhtml_response.rb +0 -20
- data/plugins/hostrec_50_redundant.rb +0 -14
- data/plugins/hostrec_60_skip.rb +0 -24
- data/plugins/time_50_ago.rb +0 -16
- data/plugins/via_50_domain.rb +0 -36
- data/public/js/jquery-1.4.2.min.js +0 -154
- data/spec/unwrap_json_spec.rb +0 -21
- data/spec/xhtml_response_spec.rb +0 -112
data/.htaccess
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
Options -Indexes
|
2
2
|
|
3
|
+
AddOutputFilterByType DEFLATE application/atom+xml
|
3
4
|
AddOutputFilterByType DEFLATE application/javascript
|
5
|
+
AddOutputFilterByType DEFLATE application/rss+xml
|
4
6
|
AddOutputFilterByType DEFLATE application/xhtml+xml
|
5
7
|
AddOutputFilterByType DEFLATE application/xml
|
6
8
|
AddOutputFilterByType DEFLATE text/css
|
data/README.textile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Site for sharing and archiving links.
|
2
2
|
|
3
3
|
* looks up url titles
|
4
|
-
* adds thumbnails for and jGrowls embedded versions of
|
4
|
+
* adds thumbnails for and jGrowls embedded versions of Imageshack, Vimeo and YouTube urls
|
5
5
|
* converts Twitter status urls to their full text and adds user thumbnail
|
6
6
|
* generates Atom and RSS feeds
|
7
7
|
* regex search
|
@@ -12,10 +12,6 @@ Site for sharing and archiving links.
|
|
12
12
|
* rack interface
|
13
13
|
* Gravatar support
|
14
14
|
|
15
|
-
!http://static.mmb.s3.amazonaws.com/murlsh_screenshot.jpg!
|
16
|
-
|
17
|
-
!http://static.mmb.s3.amazonaws.com/murlsh_iphone_screenshot.jpg!
|
18
|
-
|
19
15
|
See "http://urls.matthewm.boedicker.org/":http://urls.matthewm.boedicker.org/ for example.
|
20
16
|
|
21
17
|
h1. Installation
|
@@ -59,11 +55,9 @@ Plugin hooks
|
|
59
55
|
|
60
56
|
|Hook|Description|run() arguments|Returns|
|
61
57
|
|add_pre|called before a new url is saved|url, config hash|undefined|
|
62
|
-
|add_post|called after a new url is saved|config hash|undefined|
|
63
|
-
|hostrec|post process the domain that is shown after links|domain, url, title|text to display|
|
58
|
+
|add_post|called after a new url is saved|url, config hash|undefined|
|
64
59
|
|html_parse|parse HTML using something like Hpricot or Nokogiri|parseable|parsed HTML, only first plugin is run (cannot be chained)|
|
65
|
-
|
|
66
|
-
|via|convert a via url into a string for display|via url|via url display text|
|
60
|
+
|url_display_add|called to display additional information after urls|markup builder, url, config hash|undefined|
|
67
61
|
|
68
62
|
h1. PubSubHubbub
|
69
63
|
|
@@ -84,33 +78,9 @@ subscribe_url is what gets put in the feed as link rel="hub"
|
|
84
78
|
|
85
79
|
This will make updates to your feed show up in Google Reader instantly.
|
86
80
|
|
87
|
-
h1. Thumbnail Locators
|
88
|
-
|
89
|
-
If the url for a thumbnail image can be generated by regex search and replace
|
90
|
-
on a posted url, a rule can be added to the configuration to automatically
|
91
|
-
show a thumbnail image for it. The 'thumb_locators' config key is a hash
|
92
|
-
of Javascript regex to Javascript replacement string (which can include
|
93
|
-
captured groups). The hash key is wrapped in ^ and $ before compilation so
|
94
|
-
it must match the entire url. The regex is compiled case-insensitive.
|
95
|
-
|
96
|
-
For example:
|
97
|
-
|
98
|
-
* Show the GitHub octocat Apple touch icon
|
99
|
-
(http://github.com/apple-touch-icon.png) as a thumbnail for GitHub links
|
100
|
-
* Show a friend's Gravatar for the thumbnails of links to his blog
|
101
|
-
|
102
|
-
<pre>
|
103
|
-
<code>
|
104
|
-
thumb_locators:
|
105
|
-
(http:\/\/github\.com\/).*: $1apple-touch-icon.png
|
106
|
-
http:\/\/myfriend\.com\/.*: http://gravatar.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</code>
|
107
|
-
</pre>
|
108
|
-
|
109
81
|
h1. Design Goals
|
110
82
|
|
111
|
-
* make site fast and very cacheable, caching wrapper around calls to third party JSON APIs
|
112
83
|
* low effort required to add a url, get metadata programatically instead of requiring user to specify
|
113
|
-
* heavy lifting on the client side
|
114
84
|
* allow customization with config and plugins
|
115
85
|
* full regex search for finding saved urls
|
116
86
|
* simple security (no sessions, no cookies)
|
data/Rakefile
CHANGED
@@ -81,8 +81,10 @@ namespace :db do
|
|
81
81
|
email TEXT,
|
82
82
|
name TEXT,
|
83
83
|
title TEXT,
|
84
|
+
content_length INTEGER,
|
84
85
|
content_type TEXT,
|
85
|
-
via TEXT
|
86
|
+
via TEXT,
|
87
|
+
thumbnail_url TEXT);
|
86
88
|
")
|
87
89
|
end
|
88
90
|
|
@@ -190,8 +192,8 @@ end
|
|
190
192
|
|
191
193
|
namespace :validate do
|
192
194
|
|
193
|
-
desc 'Validate
|
194
|
-
task :
|
195
|
+
desc 'Validate HTML.'
|
196
|
+
task :html do
|
195
197
|
check_url = config['root_url']
|
196
198
|
print "validating #{check_url} : "
|
197
199
|
result = validate(check_url)
|
@@ -340,17 +342,22 @@ begin
|
|
340
342
|
activerecord 2.3.4
|
341
343
|
bcrypt-ruby 2.1.2
|
342
344
|
builder 2.1.2
|
345
|
+
flickraw 0.8.3
|
346
|
+
flog 2.5.0
|
343
347
|
hpricot 0.8.1
|
344
348
|
htmlentities 4.2.0
|
345
349
|
json 1.2.3
|
346
350
|
push-notify 0.1.0
|
347
351
|
rack 1.0.0
|
348
352
|
rack-cache 0.5.2
|
353
|
+
rack-rewrite 1.0.2
|
349
354
|
rack-throttle 0.3.0
|
350
355
|
sqlite3-ruby 1.2.1
|
351
|
-
tinyatom 0.
|
356
|
+
tinyatom 0.2.0
|
357
|
+
twitter 0.9.12
|
358
|
+
vimeo 1.2.2
|
352
359
|
}.each_slice(2) { |g,v| gemspec.add_dependency(g, ">= #{v}") }
|
353
|
-
|
360
|
+
gemspec.add_dependency('rspec', '~> 1.3')
|
354
361
|
end
|
355
362
|
rescue LoadError
|
356
363
|
puts "Jeweler not available. Install it with: gem install jeweler"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/config.ru
CHANGED
@@ -4,6 +4,7 @@ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
|
4
4
|
yaml
|
5
5
|
|
6
6
|
rack/cache
|
7
|
+
rack/rewrite
|
7
8
|
rack/throttle
|
8
9
|
|
9
10
|
murlsh
|
@@ -25,11 +26,16 @@ use Murlsh::EtagAddEncoding
|
|
25
26
|
use Rack::Deflater
|
26
27
|
use Murlsh::FarFutureExpires, :patterns => %r{\.gen\.(css|js)$}
|
27
28
|
|
28
|
-
|
29
|
-
use Murlsh::MustRevalidate, :patterns => %r{^#{Regexp.escape(
|
29
|
+
feed_url = URI.join(config.fetch('root_url'), config.fetch('feed_file'))
|
30
|
+
use Murlsh::MustRevalidate, :patterns => %r{^#{Regexp.escape(feed_url.path)}$}
|
30
31
|
|
31
|
-
use Rack::Static, :urls => %w{/css /js /swf}, :root => 'public'
|
32
|
-
use Rack::Static, :urls => %w{/atom.
|
32
|
+
use Rack::Static, :urls => %w{/css /img /js /swf}, :root => 'public'
|
33
|
+
use Rack::Static, :urls => %w{/atom.atom /podcast.rss /rss.rss}
|
34
|
+
|
35
|
+
use Rack::Rewrite do
|
36
|
+
r301 '/atom.xml', feed_url.to_s
|
37
|
+
r301 '/rss.xml', URI.join(config.fetch('root_url'), 'rss.rss').to_s
|
38
|
+
end
|
33
39
|
|
34
40
|
# use Rack::Lint
|
35
41
|
|
data/config.yaml
CHANGED
@@ -2,18 +2,19 @@
|
|
2
2
|
auth_file: murlsh_users
|
3
3
|
cache_entitystore: file:tmp/cache/rack/body
|
4
4
|
cache_metastore: file:tmp/cache/rack/meta
|
5
|
-
config_js:
|
6
|
-
|
5
|
+
config_js: []
|
6
|
+
|
7
7
|
css_files:
|
8
8
|
- css/jquery.jgrowl.css
|
9
9
|
- css/screen.css
|
10
10
|
db_file: murlsh.db
|
11
|
-
feed_file: atom.
|
11
|
+
feed_file: atom.atom
|
12
12
|
flickr_api_key:
|
13
13
|
gravatar_size: 32
|
14
14
|
js_files:
|
15
|
-
- js/jquery-1.4.
|
15
|
+
- js/jquery-1.4.3.min.js
|
16
16
|
- js/jquery.jgrowl_compressed.js
|
17
|
+
- js/twitter-text-1.0.3.js
|
17
18
|
- js/js.js
|
18
19
|
meta_tag_description: URLs found interesting by Matthew M. Boedicker
|
19
20
|
meta_tag_verify-v1:
|
@@ -25,11 +26,4 @@ pubsubhubbub_hubs: []
|
|
25
26
|
|
26
27
|
root_url: http://urls.matthewm.boedicker.org/
|
27
28
|
show_names: true
|
28
|
-
|
29
|
-
(http:\/\/(cgi\.)?ebay\.(com|co\.uk)\/).*: $1apple-touch-icon.png
|
30
|
-
(http:\/\/blog\.makezine\.com\/).*: $1apple-touch-icon.png
|
31
|
-
(http:\/\/en\.wikipedia\.org\/).*: $1apple-touch-icon.png
|
32
|
-
(http:\/\/github\.com\/).*: $1apple-touch-icon.png
|
33
|
-
(http:\/\/stackoverflow\.com\/).*: $1apple-touch-icon.png
|
34
|
-
(http:\/\/www\.nytimes\.com\/).*: $1apple-touch-icon.png
|
35
|
-
(http:\/\/www\.wired\.com\/).*: $1apple-touch-icon.png
|
29
|
+
user_agent: murlsh (http://github.com/mmb/murlsh)
|
data/lib/murlsh/dispatch.rb
CHANGED
@@ -22,8 +22,6 @@ module Murlsh
|
|
22
22
|
|
23
23
|
url_server = Murlsh::UrlServer.new(@config, db)
|
24
24
|
config_server = Murlsh::ConfigServer.new(@config)
|
25
|
-
flickr_server = Murlsh::FlickrServer.new(@config)
|
26
|
-
twitter_server = Murlsh::TwitterServer.new
|
27
25
|
|
28
26
|
root_path = URI(@config.fetch('root_url')).path
|
29
27
|
|
@@ -33,10 +31,6 @@ module Murlsh
|
|
33
31
|
[%r{^POST #{root_path}(url)?$}, url_server.method(:post)],
|
34
32
|
[%r{^HEAD #{root_path}config$}, config_server.method(:head)],
|
35
33
|
[%r{^GET #{root_path}config$}, config_server.method(:get)],
|
36
|
-
[%r{^HEAD #{root_path}flickr$}, flickr_server.method(:head)],
|
37
|
-
[%r{^GET #{root_path}flickr$}, flickr_server.method(:get)],
|
38
|
-
[%r{^HEAD #{root_path}twitter/.+$}, twitter_server.method(:head)],
|
39
|
-
[%r{^GET #{root_path}twitter/.+$}, twitter_server.method(:get)],
|
40
34
|
]
|
41
35
|
end
|
42
36
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
%w{
|
2
|
+
cgi
|
3
|
+
open-uri
|
4
|
+
}.each { |m| require m }
|
5
|
+
|
6
|
+
module Murlsh
|
7
|
+
|
8
|
+
# Fetch images from urls and store them locally.
|
9
|
+
class ImgStore
|
10
|
+
|
11
|
+
def initialize(storage_dir, options={})
|
12
|
+
@storage_dir = storage_dir
|
13
|
+
@user_agent = options[:user_agent]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Build headers to send with request.
|
17
|
+
def headers
|
18
|
+
result = {}
|
19
|
+
result['User-Agent'] = @user_agent if @user_agent
|
20
|
+
result
|
21
|
+
end
|
22
|
+
|
23
|
+
# Fetch an image from a url and store it locally.
|
24
|
+
def store(url)
|
25
|
+
local_file = CGI.escape(url)
|
26
|
+
local_path = File.join(storage_dir, local_file)
|
27
|
+
open(url, headers) do |fin|
|
28
|
+
open(local_path, 'w') { |fout| fout.write(fin.read) }
|
29
|
+
end
|
30
|
+
local_file
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :storage_dir
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/murlsh/markup.rb
CHANGED
data/lib/murlsh/plugin.rb
CHANGED
@@ -7,14 +7,10 @@ module Murlsh
|
|
7
7
|
# run arguments (url, config hash)
|
8
8
|
# * add_post - called after a new url is saved
|
9
9
|
# run arguments (config hash)
|
10
|
-
# * hostrec - called to post process the domain that shows after links
|
11
|
-
# run arguments (domain, url, title)
|
12
10
|
# * html_parse - called to parse HTML using something like Hpricot or Nokogiri
|
13
11
|
# run arguments (parseable)
|
14
|
-
# *
|
15
|
-
# run arguments (
|
16
|
-
# * via - called to convert a via url into a string for display
|
17
|
-
# run arguments (via url)
|
12
|
+
# * url_display_add - called to display additional information after urls
|
13
|
+
# run arguments (markup builder, url, config hash)
|
18
14
|
class Plugin
|
19
15
|
|
20
16
|
# Called when a plugin class inherits from this class (the way plugins
|
data/lib/murlsh/uri_ask.rb
CHANGED
@@ -14,33 +14,19 @@ module Murlsh
|
|
14
14
|
# URI mixin.
|
15
15
|
module UriAsk
|
16
16
|
|
17
|
-
# Get the content
|
17
|
+
# Get the content length.
|
18
18
|
#
|
19
19
|
# Options:
|
20
20
|
# * :failproof - if true hide all exceptions and return empty string on failure
|
21
21
|
# * :headers - hash of headers to send in request
|
22
|
-
def
|
23
|
-
return @content_type if defined?(@content_type)
|
24
|
-
options[:headers] = default_headers.merge(options.fetch(:headers, {}))
|
25
|
-
|
26
|
-
content_type = ''
|
27
|
-
Murlsh::failproof(options) do
|
28
|
-
# try head first to save bandwidth
|
29
|
-
http = Net::HTTP.new(host, port)
|
30
|
-
http.use_ssl = (scheme == 'https')
|
31
|
-
|
32
|
-
resp = http.request_head(path_query, options[:headers])
|
22
|
+
def content_length(options={}); header('content-length', options); end
|
33
23
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|
42
|
-
@content_type = content_type
|
43
|
-
end
|
24
|
+
# Get the content type.
|
25
|
+
#
|
26
|
+
# Options:
|
27
|
+
# * :failproof - if true hide all exceptions and return empty string on failure
|
28
|
+
# * :headers - hash of headers to send in request
|
29
|
+
def content_type(options={}); header('content-type', options); end
|
44
30
|
|
45
31
|
# Get the HTML title.
|
46
32
|
#
|
@@ -134,6 +120,64 @@ module Murlsh
|
|
134
120
|
HTMLEntities.new.decode(Iconv.conv('utf-8', @charset, s))
|
135
121
|
end
|
136
122
|
|
123
|
+
# Get the value of a response header.
|
124
|
+
#
|
125
|
+
# Options:
|
126
|
+
# * :failproof - if true hide all exceptions and return empty string on failure
|
127
|
+
# * :headers - hash of headers to send in request
|
128
|
+
def header(header_name, options={})
|
129
|
+
result = [*head_headers(options)[header_name]][0]
|
130
|
+
result = get_headers(options)[header_name] if !result or result.empty?
|
131
|
+
result || ''
|
132
|
+
end
|
133
|
+
|
134
|
+
# Get and cache response headers returned by HTTP HEAD for this URI.
|
135
|
+
#
|
136
|
+
# Return hash values are lists.
|
137
|
+
#
|
138
|
+
# Options:
|
139
|
+
# * :failproof - if true hide all exceptions and return empty hash on failure
|
140
|
+
# * :headers - hash of headers to send in request
|
141
|
+
def head_headers(options={})
|
142
|
+
return @head_headers if defined?(@head_headers)
|
143
|
+
|
144
|
+
request_headers = default_headers.merge(options.fetch(:headers, {}))
|
145
|
+
|
146
|
+
response_headers = {}
|
147
|
+
Murlsh::failproof(options) do
|
148
|
+
http = Net::HTTP.new(host, port)
|
149
|
+
http.use_ssl = (scheme == 'https')
|
150
|
+
|
151
|
+
resp = http.request_head(path_query, request_headers)
|
152
|
+
|
153
|
+
if Net::HTTPSuccess === resp
|
154
|
+
response_headers = resp.to_hash
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
@head_headers = response_headers
|
159
|
+
end
|
160
|
+
|
161
|
+
# Get and cache response headers returned by HTTP GET for this URI.
|
162
|
+
#
|
163
|
+
# Return hash values are single strings.
|
164
|
+
#
|
165
|
+
# Options:
|
166
|
+
# * :failproof - if true hide all exceptions and return empty hash on failure
|
167
|
+
# * :headers - hash of headers to send in request
|
168
|
+
def get_headers(options={})
|
169
|
+
return @get_headers if defined?(@get_headers)
|
170
|
+
|
171
|
+
request_headers = default_headers.merge(options.fetch(:headers, {}))
|
172
|
+
|
173
|
+
response_headers = {}
|
174
|
+
# use open-uri instead of Net::HTTP because it handles redirects
|
175
|
+
Murlsh::failproof(options) do
|
176
|
+
response_headers = self.open(request_headers) { |f| f.meta }
|
177
|
+
end
|
178
|
+
@get_headers = response_headers
|
179
|
+
end
|
180
|
+
|
137
181
|
end
|
138
182
|
|
139
183
|
end
|
data/lib/murlsh/url.rb
CHANGED
@@ -31,24 +31,6 @@ module Murlsh
|
|
31
31
|
email and name and email == other.email and name == other.name
|
32
32
|
end
|
33
33
|
|
34
|
-
# Return text showing what domain a link goes to.
|
35
|
-
def hostrec
|
36
|
-
domain = Murlsh::failproof { URI(url).domain }
|
37
|
-
|
38
|
-
domain = Murlsh::Plugin.hooks('hostrec').inject(domain) {
|
39
|
-
|result,plugin| plugin.run(result, url, title) }
|
40
|
-
|
41
|
-
yield domain if domain
|
42
|
-
end
|
43
|
-
|
44
|
-
# Yield the url that the url came from.
|
45
|
-
def viarec; Murlsh::failproof { yield URI(via) } if via; end
|
46
|
-
|
47
|
-
# Return true if this url is an image.
|
48
|
-
def is_image?
|
49
|
-
%w{image/gif image/jpeg image/png}.include?(content_type)
|
50
|
-
end
|
51
|
-
|
52
34
|
end
|
53
35
|
|
54
36
|
end
|
data/lib/murlsh/url_body.rb
CHANGED
@@ -8,9 +8,10 @@ module Murlsh
|
|
8
8
|
class UrlBody < Builder::XmlMarkup
|
9
9
|
include Murlsh::Markup
|
10
10
|
|
11
|
-
def initialize(config, db, req)
|
12
|
-
@config, @db, @req, @q
|
13
|
-
|
11
|
+
def initialize(config, db, req, content_type='text/html')
|
12
|
+
@config, @db, @req, @q, @content_type =
|
13
|
+
config, db, req, req.params['q'], content_type
|
14
|
+
super(:indent => @config['html_indent'] || 0)
|
14
15
|
end
|
15
16
|
|
16
17
|
# Fetch urls base on query string parameters.
|
@@ -33,14 +34,9 @@ module Murlsh
|
|
33
34
|
|
34
35
|
# Url list page body builder.
|
35
36
|
def each
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
yield html(:xmlns => 'http://www.w3.org/1999/xhtml',
|
41
|
-
:'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
42
|
-
:'xsi:schemaLocation' => 'http://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd',
|
43
|
-
:'xml:lang' => 'en') {
|
37
|
+
declare! :DOCTYPE, :html
|
38
|
+
|
39
|
+
yield html(:lang => 'en') {
|
44
40
|
headd
|
45
41
|
body {
|
46
42
|
ul(:id => 'urls') {
|
@@ -59,22 +55,17 @@ module Murlsh
|
|
59
55
|
@config.fetch('show_names', false) and mu.name
|
60
56
|
end
|
61
57
|
|
58
|
+
if mu.thumbnail_url
|
59
|
+
murlsh_img(:src => mu.thumbnail_url,
|
60
|
+
:text => mu.title_stripped, :class => 'thumb')
|
61
|
+
end
|
62
|
+
|
62
63
|
a(mu.title_stripped, :href => mu.url, :class => 'm')
|
63
64
|
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
mu.viarec do |via|
|
68
|
-
display_via = Murlsh::Plugin.hooks('via').inject(
|
69
|
-
via) { |result,plugin| plugin.run(result) }
|
70
|
-
span(:class => 'via') {
|
71
|
-
text!(' via '); a(display_via, :href => via)
|
72
|
-
}
|
65
|
+
Murlsh::Plugin.hooks('url_display_add') do |p|
|
66
|
+
p.run(self, mu, @config)
|
73
67
|
end
|
74
68
|
|
75
|
-
display_time = Murlsh::Plugin.hooks('time').inject(
|
76
|
-
mu.time) { |result,plugin| plugin.run(result) }
|
77
|
-
span(", #{display_time}", :class => 'date') if display_time
|
78
69
|
last = mu
|
79
70
|
}
|
80
71
|
end
|
@@ -94,6 +85,7 @@ module Murlsh
|
|
94
85
|
def headd
|
95
86
|
head {
|
96
87
|
titlee
|
88
|
+
meta :'http-equiv' => 'Content-Type', :content => @content_type
|
97
89
|
metas(@config.select { |k,v| k =~ /^meta_tag_/ and v }.
|
98
90
|
map { |k,v| [k.sub('meta_tag_', ''), v] })
|
99
91
|
css(@config['css_compressed'] || @config['css_files'])
|
data/lib/murlsh/url_server.rb
CHANGED
@@ -20,16 +20,16 @@ module Murlsh
|
|
20
20
|
# Respond to a GET request. Return a page of urls based on the query
|
21
21
|
# string parameters.
|
22
22
|
def get(req)
|
23
|
-
|
23
|
+
last_db_update = File::Stat.new(@config['db_file']).mtime
|
24
24
|
|
25
|
-
resp
|
25
|
+
resp = Rack::Response.new
|
26
26
|
|
27
|
-
last_db_update = File::Stat.new(@config['db_file']).mtime
|
28
27
|
resp['Cache-Control'] = 'must-revalidate, max-age=0'
|
28
|
+
resp['Content-Type'] = 'text/html; charset=utf-8'
|
29
29
|
resp['ETag'] = "W/\"#{last_db_update.to_i}#{req.params.sort}\""
|
30
30
|
resp['Last-Modified'] = last_db_update.httpdate
|
31
31
|
|
32
|
-
resp.body = Murlsh::UrlBody.new(@config, @db, req)
|
32
|
+
resp.body = Murlsh::UrlBody.new(@config, @db, req, resp['Content-Type'])
|
33
33
|
|
34
34
|
resp
|
35
35
|
end
|
@@ -55,7 +55,7 @@ module Murlsh
|
|
55
55
|
raise ActiveRecord::RecordInvalid.new(mu) unless mu.valid?
|
56
56
|
Murlsh::Plugin.hooks('add_pre') { |p| p.run(mu, @config) }
|
57
57
|
mu.save!
|
58
|
-
Murlsh::Plugin.hooks('add_post') { |p| p.run(@config) }
|
58
|
+
Murlsh::Plugin.hooks('add_post') { |p| p.run(mu, @config) }
|
59
59
|
response_body, response_code = [mu], 200
|
60
60
|
rescue ActiveRecord::RecordInvalid => error
|
61
61
|
response_body = {
|