murlsh 0.11.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 = {
|