murlsh 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +4 -0
  2. data/.htaccess +0 -3
  3. data/Gemfile +41 -0
  4. data/README.textile +68 -6
  5. data/Rakefile +65 -152
  6. data/config.ru +13 -2
  7. data/config.yaml +9 -4
  8. data/db/migrate/20110213023123_init.rb +20 -0
  9. data/lib/murlsh/atom_body.rb +78 -0
  10. data/lib/murlsh/atom_server.rb +38 -0
  11. data/lib/murlsh/auth.rb +12 -0
  12. data/lib/murlsh/build_query.rb +1 -1
  13. data/lib/murlsh/cat_files.rb +17 -0
  14. data/lib/murlsh/delicious_parse.rb +1 -0
  15. data/lib/murlsh/dispatch.rb +25 -11
  16. data/lib/murlsh/etag_add_encoding.rb +1 -1
  17. data/lib/murlsh/feed_body.rb +36 -0
  18. data/lib/murlsh/img_store.rb +27 -28
  19. data/lib/murlsh/install.rb +1 -0
  20. data/lib/murlsh/json_body.rb +5 -2
  21. data/lib/murlsh/json_server.rb +9 -13
  22. data/lib/murlsh/m3u_body.rb +28 -0
  23. data/lib/murlsh/m3u_server.rb +50 -0
  24. data/lib/murlsh/markup.rb +1 -1
  25. data/lib/murlsh/plugin.rb +5 -0
  26. data/lib/murlsh/podcast_server.rb +44 -0
  27. data/lib/murlsh/pop_server.rb +78 -0
  28. data/lib/murlsh/random_server.rb +41 -0
  29. data/lib/murlsh/rss_body.rb +46 -0
  30. data/lib/murlsh/rss_server.rb +38 -0
  31. data/lib/murlsh/search_conditions.rb +2 -2
  32. data/lib/murlsh/uri_ask.rb +2 -2
  33. data/lib/murlsh/url_body.rb +21 -6
  34. data/lib/murlsh/url_result_set.rb +2 -2
  35. data/lib/murlsh/url_server.rb +19 -16
  36. data/lib/murlsh/write_ordered_hash.rb +17 -0
  37. data/lib/murlsh.rb +13 -2
  38. data/murlsh.gemspec +41 -194
  39. data/plugins/add_post_60_notify_hubs.rb +3 -2
  40. data/plugins/add_pre_30_unajax_twitter.rb +1 -1
  41. data/plugins/add_pre_40_thumbnail_shortcuts.rb +23 -0
  42. data/plugins/add_pre_45_supplied_thumbnail.rb +4 -9
  43. data/plugins/add_pre_50_media_thumbnail.rb +4 -9
  44. data/plugins/add_pre_50_open_graph_image.rb +4 -8
  45. data/plugins/add_pre_60_github_title.rb +1 -1
  46. data/plugins/add_pre_65_html_thumb.rb +3 -8
  47. data/plugins/add_pre_65_img_thumb.rb +4 -9
  48. data/plugins/avatar_50_gravatar.rb +2 -1
  49. data/plugins/store_asset_40_s3.rb +40 -0
  50. data/plugins/store_asset_50_local.rb +22 -0
  51. data/public/js/js.js +0 -7
  52. data/spec/auth_spec.rb +7 -0
  53. data/spec/cat_files_spec.rb +49 -0
  54. data/spec/img_store_spec.rb +24 -8
  55. metadata +119 -76
  56. data/VERSION +0 -1
  57. data/lib/murlsh/build_md5.rb +0 -12
  58. data/lib/murlsh/head_from_get.rb +0 -15
  59. data/plugins/add_post_50_update_feed.rb +0 -84
  60. data/plugins/add_post_50_update_m3u.rb +0 -35
  61. data/plugins/add_post_50_update_podcast.rb +0 -44
  62. data/plugins/add_post_50_update_rss.rb +0 -51
  63. data/plugins/add_pre_60_s3_image.rb +0 -35
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *~
2
+ \#*#
3
+ \.#*
4
+ *\.gem
data/.htaccess CHANGED
@@ -1,11 +1,8 @@
1
1
  Options -Indexes
2
2
 
3
- AddOutputFilterByType DEFLATE application/atom+xml
4
3
  AddOutputFilterByType DEFLATE application/javascript
5
- AddOutputFilterByType DEFLATE application/rss+xml
6
4
  AddOutputFilterByType DEFLATE application/xhtml+xml
7
5
  AddOutputFilterByType DEFLATE application/xml
8
- AddOutputFilterByType DEFLATE audio/x-mpegurl
9
6
  AddOutputFilterByType DEFLATE text/css
10
7
  AddOutputFilterByType DEFLATE text/html
11
8
 
data/Gemfile ADDED
@@ -0,0 +1,41 @@
1
+ source :rubygems
2
+
3
+ # This does not use 'gemspec' because it creates a Gemfile.lock that treats
4
+ # murlsh as a "gem" and will not work on Heroku, which sees murlsh as an
5
+ # "app".
6
+
7
+ # Dependencies duplicated in gemspec and here until a better solution is
8
+ # found.
9
+
10
+ %w{
11
+ activerecord >= 2.3.4
12
+ aws-s3 ~> 0.6
13
+ bcrypt-ruby >= 2.1.2
14
+ builder > 0
15
+ htmlentities >= 4.2.0
16
+ json >= 1.2.3
17
+ nokogiri ~> 1.0
18
+ plumnailer >= 0.1.3
19
+ postrank-uri ~> 1.0
20
+ public_suffix_service ~> 0.0
21
+ push-notify >= 0.1.0
22
+ rack >= 1.0.0
23
+ rack-cache >= 0.5.2
24
+ rack-rewrite >= 1.0.2
25
+ rack-throttle >= 0.3.0
26
+ rmagick >= 1.15.14
27
+ rmail ~> 1.0
28
+ sqlite3 ~> 1.3
29
+ tinyatom >= 0.3.4
30
+ treetop ~> 1.4
31
+ twitter >= 0.9.12
32
+ }.each_slice(3) { |g,o,v| gem g, "#{o} #{v}" }
33
+
34
+ group :development do
35
+ %w{
36
+ fakeweb ~> 1.3
37
+ flog >= 2.5.0
38
+ rack-test ~> 0.5
39
+ rspec ~> 2.0
40
+ }.each_slice(3) { |g,o,v| gem g, "#{o} #{v}" }
41
+ end
data/README.textile CHANGED
@@ -6,7 +6,7 @@ Host your bookmarks or maintain a link blog.
6
6
  * generates Atom and RSS feeds
7
7
  * generates podcast RSS feed and m3u file for all audio urls
8
8
  * generates json and jsonp feeds for client-side inclusion in other sites
9
- * search
9
+ * search, all output formats can be filtered by search criteria
10
10
  * uses HTML5 audio for mp3 and ogg urls
11
11
  * looks good on iPhone
12
12
  * PubSubHubbub notification
@@ -14,6 +14,7 @@ Host your bookmarks or maintain a link blog.
14
14
  * rack interface
15
15
  * Gravatar support
16
16
  * generates import scripts from delicious api exports
17
+ * optionally store thumbnails in S3
17
18
 
18
19
  See "http://urls.matthewm.boedicker.org/":http://urls.matthewm.boedicker.org/ for example.
19
20
 
@@ -34,13 +35,60 @@ rake init
34
35
  </code>
35
36
  </pre>
36
37
 
38
+ h2. Heroku
39
+
40
+ <pre>
41
+ <code>
42
+ gem install heroku
43
+ heroku keys:add
44
+ </code>
45
+ </pre>
46
+
47
+ Create a fork on github and clone it or clone public url:
48
+
49
+ <pre>
50
+ <code>
51
+ git clone git://github.com/mmb/murlsh.git
52
+ cd murlsh
53
+ bundle install
54
+ heroku create <choose a name>
55
+ rake heroku:config
56
+ heroku info
57
+ rake config[root_url,<your app's Heroku url>]
58
+ rake config[s3_bucket,<your S3 bucket name>]
59
+ rake config[s3_id,<your S3 id>]
60
+ rake config[s3_secret,<your S3 secret>]
61
+ </code>
62
+ </pre>
63
+
64
+ S3 is used for thumbnail storage because Heroku cannot write local files.
65
+
66
+ Other config in config.yaml is optional.
67
+
68
+ <pre>
69
+ <code>
70
+ rake user:add
71
+ git add .
72
+ git commit
73
+ git push heroku master
74
+ heroku rake db:migrate
75
+ </code>
76
+ </pre>
77
+
37
78
  h2. Development
38
79
 
39
- * Create a fork and check it out
40
- * edit config.yaml
41
- * rake init
42
- * rackup
43
- * open http://localhost:9292/
80
+ Create a fork on Github and clone it.
81
+
82
+ <pre>
83
+ <code>
84
+ rake config[root_url,http://localhost:9292/]
85
+ rake db:migrate
86
+ rake user:add
87
+ rackup
88
+ </code>
89
+ </pre>
90
+
91
+ Browse to http://localhost:9292/
44
92
 
45
93
  h1. Updating
46
94
 
@@ -60,6 +108,18 @@ h2. Recent urls
60
108
  * http://your_root/json.json
61
109
  * http://your_root/json.json?callback=x (jsonp)
62
110
 
111
+ h1. Thumbnails
112
+
113
+ Thumbnail images are generated from added urls using plumnailer. They are
114
+ scaled down to 'thumbnail_max_side' in config.yaml and stored locally.
115
+
116
+ Thumbnails can also be manually specified by passing their url as the
117
+ 'thumbnail' parameter when adding a url. They are also scaled and stored
118
+ locally.
119
+
120
+ The plugin add_pre_40_thumbnail_shortcuts.rb can be used to specify
121
+ short names for frequently used thumbnail urls that can be passed in instead.
122
+
63
123
  h1. Plugins
64
124
 
65
125
  Classes in the plugins directory can be used to change behavior at certain
@@ -79,7 +139,9 @@ Plugin hooks
79
139
  |add_pre|called before a new url is saved|url, config hash|undefined|
80
140
  |add_post|called after a new url is saved|url, config hash|undefined|
81
141
  |avatar|called to get an avatar url from an email md5 sum|avatar url, url, config hash|avatar url|
142
+ |store_asset|store an asset somewhere where it can be loaded by url|name, data, config hash|asset url if successfully stored|
82
143
  |url_display_add|called to display additional information after urls|markup builder, url, config hash|undefined|
144
+ |url_display_pre|called to modify a url on-the-fly before display, does not change database|url, rack request, config hash|undefined|
83
145
 
84
146
  h1. PubSubHubbub
85
147
 
data/Rakefile CHANGED
@@ -1,8 +1,8 @@
1
1
  $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
2
 
3
- require 'cgi'
4
3
  require 'digest/md5'
5
4
  require 'net/http'
5
+ require 'logger'
6
6
  require 'open-uri'
7
7
  require 'pp'
8
8
  require 'set'
@@ -11,18 +11,23 @@ require 'yaml'
11
11
 
12
12
  require 'active_record'
13
13
  require 'RMagick'
14
- require 'sqlite3'
15
14
 
16
15
  require 'murlsh'
17
16
 
18
17
  def gem_not_found(gem_name)
19
- puts "#{gem_name} not found, install it with: gem install #{gem_name}"
18
+ puts "#{gem_name} gem not found"
20
19
  end
21
20
 
22
21
  config = YAML.load_file('config.yaml')
23
22
 
23
+ # for Heroku
24
+ db_config_file = File.join(File.dirname(__FILE__), 'config', 'database.yml')
25
+ if File.exist?(db_config_file)
26
+ config['db'] = YAML.load_file(db_config_file)['production']
27
+ end
28
+
24
29
  desc 'Initialize a new installation.'
25
- task :init => %w{db:init user:add compress} do
30
+ task :init => %w{db:migrate user:add compress} do
26
31
  puts <<-eos
27
32
 
28
33
  Things you might want to do now:
@@ -46,8 +51,7 @@ namespace :db do
46
51
 
47
52
  desc 'Delete the last url added.'
48
53
  task :delete_last_url do
49
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
50
- :database => config.fetch('db_file'))
54
+ ActiveRecord::Base.establish_connection config.fetch('db')
51
55
 
52
56
  last = Murlsh::Url.find(:last, :order => 'time')
53
57
  pp last
@@ -57,46 +61,43 @@ namespace :db do
57
61
 
58
62
  desc 'Check for duplicate URLs.'
59
63
  task :dupcheck do
60
- db = SQLite3::Database.new(config.fetch('db_file'))
61
- db.results_as_hash = true
64
+ ActiveRecord::Base.establish_connection config.fetch('db')
65
+
62
66
  h = {}
63
- db.execute('SELECT * FROM urls').each do |r|
64
- h[r['url']] = h.fetch(r['url'], []).push([r['id'], r['time']])
67
+ Murlsh::Url.all.each do |mu|
68
+ h[mu.url] = h.fetch(mu.url, []).push([mu.id, mu.time])
65
69
  end
66
70
  h.find_all { |k,v| v.size > 1 }.each do |k,v|
67
71
  puts k
68
- v.each { |id,time| puts " #{id} #{time}" }
72
+ v.each { |id,time| puts " id #{id} (#{time})" }
69
73
  end
70
74
  end
71
75
 
72
- desc 'Create an empty database.'
73
- task :init do
74
- puts "creating #{config.fetch('db_file')}"
75
- db = SQLite3::Database.new(config.fetch('db_file'))
76
- db.execute 'CREATE TABLE urls (
77
- id INTEGER PRIMARY KEY,
78
- time TIMESTAMP,
79
- url TEXT,
80
- email TEXT,
81
- name TEXT,
82
- title TEXT,
83
- content_length INTEGER,
84
- content_type TEXT,
85
- via TEXT,
86
- thumbnail_url TEXT);
87
- '
88
- db.execute 'CREATE INDEX IF NOT EXISTS urls_time_desc ON urls (time DESC);'
76
+ desc 'Migrate the database.'
77
+ task :migrate do
78
+ ActiveRecord::Base.establish_connection config.fetch('db')
79
+ ActiveRecord::Base.logger = Logger.new($stdout)
80
+ ActiveRecord::Migration.verbose = true
81
+ ActiveRecord::Migrator.migrate 'db/migrate'
89
82
  end
90
83
 
91
84
  desc 'Interact with the database.'
92
85
  task :shell do
93
- exec "sqlite3 #{config['db_file']}"
86
+ db = config.fetch('db')
87
+ command = case db.fetch('adapter')
88
+ when 'sqlite3'; "sqlite3 #{db.fetch('database')}"
89
+ end
90
+
91
+ if command
92
+ exec command
93
+ else
94
+ puts "Don't know how to launch shell for database '#{db.fetch('adapter')}'"
95
+ end
94
96
  end
95
97
 
96
98
  desc 'Search urls and titles in the database.'
97
99
  task :grep, :search do |t,args|
98
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
99
- :database => config.fetch('db_file'))
100
+ ActiveRecord::Base.establish_connection config.fetch('db')
100
101
 
101
102
  like = "%#{args.search}%"
102
103
  Murlsh::Url.all(:conditions =>
@@ -140,7 +141,7 @@ begin
140
141
  t.verbose = true
141
142
  end
142
143
  rescue LoadError
143
- puts 'rspec gem ~> 2.0 not found, to enable test task: gem install rspec'
144
+ gem_not_found 'rspec'
144
145
  end
145
146
 
146
147
  desc 'Test remote title fetch for a URL and show errors.'
@@ -151,8 +152,7 @@ end
151
152
 
152
153
  desc 'Try to fetch the title for a url and update it in the database.'
153
154
  task :title_fetch, :url_id do |t, args|
154
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
155
- :database => config.fetch('db_file'))
155
+ ActiveRecord::Base.establish_connection config.fetch('db')
156
156
  url = Murlsh::Url.find(args.url_id)
157
157
  puts "Url: #{url.url}"
158
158
  puts "Previous title: #{url.title}"
@@ -176,51 +176,6 @@ namespace :user do
176
176
 
177
177
  end
178
178
 
179
- # Validate a document with the W3C validation service.
180
- def validate_html(check_url, options={})
181
- opts = {
182
- :validator_host => 'validator.w3.org',
183
- :validator_port => 80,
184
- :validator_path =>
185
- "/check?uri=#{CGI::escape(check_url)}&charset=(detect+automatically)&doctype=Inline&group=0",
186
- }.merge options
187
-
188
- net_http = Net::HTTP.new(opts[:validator_host], opts[:validator_port])
189
- # net_http.set_debug_output(STDOUT)
190
-
191
- net_http.start do |http|
192
- resp = http.request_head(opts[:validator_path])
193
- result = {
194
- :response => resp
195
- }
196
- if Net::HTTPSuccess === resp
197
- result.merge!(
198
- :status => resp['X-W3C-Validator-Status'],
199
- :errors => resp['X-W3C-Validator-Errors'],
200
- :warnings => resp['X-W3C-Validator-Warnings']
201
- )
202
- end
203
- result
204
- end
205
-
206
- end
207
-
208
- namespace :validate do
209
-
210
- desc 'Validate HTML.'
211
- task :html do
212
- check_url = config['root_url']
213
- print "validating #{check_url} : "
214
- result = validate_html(check_url)
215
- if Net::HTTPSuccess === result[:response]
216
- puts "#{result[:status]} (#{result[:errors]} errors, #{result[:warnings]} warnings)"
217
- else
218
- puts result[:response]
219
- end
220
- end
221
-
222
- end
223
-
224
179
  desc 'Generate a shell script that will post a new url.'
225
180
  task :post_sh do
226
181
  puts <<EOS
@@ -238,25 +193,14 @@ curl \\
238
193
  EOS
239
194
  end
240
195
 
241
- # Concatenate some files and return the result as a string.
242
- def cat(in_files, sep=nil)
243
- result = ''
244
- in_files.each do |fname|
245
- open(fname) do |h|
246
- while (line = h.gets) do; result << line; end
247
- result << sep if sep
248
- end
249
- end
250
- result
251
- end
252
-
253
196
  directory 'public/css'
254
197
 
255
198
  namespace :css do
256
199
 
257
200
  desc 'Combine and compress css.'
258
201
  task :compress => ['public/css'] do
259
- combined = cat(config['css_files'].map { |x| "public/#{x}" }, "\n")
202
+ combined = Murlsh.cat_files(
203
+ config['css_files'].map { |x| "public/#{x}" }, "\n")
260
204
 
261
205
  md5sum = Digest::MD5.hexdigest(combined)
262
206
 
@@ -271,11 +215,7 @@ namespace :css do
271
215
 
272
216
  unless config['css_compressed'] == compressed_url
273
217
  config['css_compressed'] = compressed_url
274
- config.extend(Murlsh::YamlOrderedHash)
275
- config.each_value do |v|
276
- v.extend(Murlsh::YamlOrderedHash) if v.is_a?(Hash)
277
- end
278
- open('config.yaml', 'w') { |f| YAML.dump(config, f) }
218
+ Murlsh.write_ordered_hash config, 'config.yaml'
279
219
  puts "updated config with css_compressed = #{compressed_url}"
280
220
  end
281
221
  end
@@ -290,7 +230,8 @@ namespace :js do
290
230
 
291
231
  desc 'Combine and compress javascript.'
292
232
  task :compress => ['public/js'] do
293
- combined = cat(config['js_files'].map { |x| "public/#{x}" } )
233
+ combined = Murlsh.cat_files(
234
+ config['js_files'].map { |x| "public/#{x}" } )
294
235
 
295
236
  compressed = Net::HTTP.post_form(
296
237
  URI.parse('http://closure-compiler.appspot.com/compile'), {
@@ -313,11 +254,7 @@ namespace :js do
313
254
 
314
255
  unless config['js_compressed'] == compressed_url
315
256
  config['js_compressed'] = compressed_url
316
- config.extend(Murlsh::YamlOrderedHash)
317
- config.each_value do |v|
318
- v.extend(Murlsh::YamlOrderedHash) if v.is_a?(Hash)
319
- end
320
- open('config.yaml', 'w') { |f| YAML.dump(config, f) }
257
+ Murlsh.write_ordered_hash config, 'config.yaml'
321
258
  puts "updated config with js_compressed = #{compressed_url}"
322
259
  end
323
260
  end
@@ -326,7 +263,7 @@ namespace :js do
326
263
  task :jslint do
327
264
  local_jslint = 'jslint_rhino.js'
328
265
  open(local_jslint, 'w') do |f|
329
- f.write(cat(%w{
266
+ f.write(Murlsh.cat_files(%w{
330
267
  https://github.com/AndyStricker/JSLint/raw/rhinocmdline/fulljslint.js
331
268
  https://github.com/AndyStricker/JSLint/raw/rhinocmdline/rhino.js
332
269
  }))
@@ -352,11 +289,10 @@ namespace :thumb do
352
289
 
353
290
  desc 'Check that local thumbnails in database are consistent with filesystem.'
354
291
  task :check do
355
- ActiveRecord::Base.establish_connection :adapter => 'sqlite3',
356
- :database => config.fetch('db_file')
292
+ ActiveRecord::Base.establish_connection config.fetch('db')
357
293
  used_thumbnails = Set.new
358
294
  Murlsh::Url.all(
359
- :conditions => "thumbnail_url like 'img/thumb/%'").each do |u|
295
+ :conditions => "thumbnail_url LIKE 'img/thumb/%'").each do |u|
360
296
  identity = "url #{u.id} (#{u.url})"
361
297
 
362
298
  path = File.join(%w{public}.concat(File.split(u.thumbnail_url)))
@@ -424,50 +360,27 @@ EOS
424
360
 
425
361
  end
426
362
 
427
- begin
428
- require 'jeweler'
429
- Jeweler::Tasks.new do |gemspec|
430
- gemspec.name = 'murlsh'
431
- gemspec.summary = 'Host your bookmarks or maintain a link blog'
432
- gemspec.description = 'Host your bookmarks or maintain a link blog'
433
- gemspec.email = 'matthewm@boedicker.org'
434
- gemspec.homepage = 'http://github.com/mmb/murlsh'
435
- gemspec.authors = ['Matthew M. Boedicker']
436
- gemspec.executables = %w{murlsh}
437
-
438
- # gemspec.signing_key = '/home/mmb/src/keys/gem-private_key.pem'
439
- # gemspec.cert_chain = %w{/home/mmb/src/keys/gem-public_cert.pem}
440
-
441
- %w{
442
- activerecord >= 2.3.4
443
- bcrypt-ruby >= 2.1.2
444
- builder >= 2.1.2
445
- htmlentities >= 4.2.0
446
- json >= 1.2.3
447
- nokogiri ~> 1.0
448
- plumnailer >= 0.1.0
449
- postrank-uri ~> 1.0
450
- public_suffix_service ~> 0.0
451
- push-notify >= 0.1.0
452
- rack >= 1.0.0
453
- rack-cache >= 0.5.2
454
- rack-rewrite >= 1.0.2
455
- rack-throttle >= 0.3.0
456
- rmagick >= 1.15.14
457
- sqlite3 ~> 1.3
458
- tinyatom >= 0.3.3
459
- treetop ~> 1.4
460
- twitter >= 0.9.12
461
- }.each_slice(3) { |g,o,v| gemspec.add_dependency(g, "#{o} #{v}") }
462
- %w{
463
- fakeweb ~> 1.3
464
- flog >= 2.5.0
465
- rack-test ~> 0.5
466
- rspec ~> 2.0
467
- }.each_slice(3) do |g,o,v|
468
- gemspec.add_development_dependency(g, "#{o} #{v}")
469
- end
363
+ desc 'Set options in config.yaml.'
364
+ task :config, :key, :value do |t, args|
365
+ orig_value = config[args.key]
366
+ if args.value != orig_value
367
+ config[args.key] = args.value
368
+ Murlsh.write_ordered_hash config, 'config.yaml'
369
+ puts "updated '#{args.key}' '#{orig_value}' => '#{args.value}'"
370
+ else
371
+ puts "'#{args.key}' is already set to '#{args.value}'"
470
372
  end
471
- rescue LoadError
472
- puts "Jeweler not available. Install it with: gem install jeweler"
373
+ end
374
+
375
+ namespace :heroku do
376
+
377
+ desc 'Set config options for deployment on Heroku.'
378
+ task :config => %w{compress} do
379
+ config.delete 'cache_entitystore'
380
+ config.delete 'cache_metastore'
381
+
382
+ Murlsh.write_ordered_hash config, 'config.yaml'
383
+ puts 'removed cache_entitystore and cache_metastore from config, Rack::Cache disabled'
384
+ end
385
+
473
386
  end
data/config.ru CHANGED
@@ -3,6 +3,7 @@ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
3
3
  require 'uri'
4
4
  require 'yaml'
5
5
 
6
+ require 'rack'
6
7
  require 'rack/cache'
7
8
  require 'rack/rewrite'
8
9
  require 'rack/throttle'
@@ -11,18 +12,29 @@ require 'murlsh'
11
12
 
12
13
  config = YAML.load_file('config.yaml')
13
14
 
15
+ # for Heroku
16
+ db_config_file = File.join(File.dirname(__FILE__), 'config', 'database.yml')
17
+ if File.exist?(db_config_file)
18
+ config['db'] = YAML.load_file(db_config_file)['production']
19
+ end
20
+
14
21
  # use Rack::ShowExceptions
15
22
  # no more than 1024 requests per day per ip
16
23
  use Rack::Throttle::Daily, :max => 1024
17
- if config.key?('cache_metastore') and config.key?('cache_entitystore')
24
+
25
+ if !config['cache_metastore'].to_s.empty? and
26
+ !config['cache_entitystore'].to_s.empty?
18
27
  use Rack::Cache,
19
28
  :verbose => true,
20
29
  :metastore => config['cache_metastore'],
21
30
  :entitystore => config['cache_entitystore']
22
31
  end
32
+
23
33
  use Rack::ConditionalGet
24
34
  use Murlsh::EtagAddEncoding
25
35
  use Rack::Deflater
36
+ use Rack::Head
37
+ use Rack::ETag
26
38
  use Murlsh::FarFutureExpires, :patterns => [
27
39
  %r{[\da-z]{32}\.(?:gif|jpe?g|png)$}i,
28
40
  %r{\.gen\.(css|js)$}
@@ -32,7 +44,6 @@ feed_url = URI.join(config.fetch('root_url'), config.fetch('feed_file'))
32
44
  use Murlsh::MustRevalidate, :patterns => %r{^#{Regexp.escape(feed_url.path)}$}
33
45
 
34
46
  use Rack::Static, :urls => %w{/css/ /img/ /js/}, :root => 'public'
35
- use Rack::Static, :urls => %w{/atom.atom /m3u.m3u /podcast.rss /rss.rss}
36
47
 
37
48
  use Rack::Rewrite do
38
49
  r301 '/atom.xml', feed_url.to_s
data/config.yaml CHANGED
@@ -5,7 +5,9 @@ cache_metastore: file:tmp/cache/rack/meta
5
5
  css_files:
6
6
  - css/jquery.jgrowl.css
7
7
  - css/screen.css
8
- db_file: murlsh.db
8
+ db:
9
+ adapter: sqlite3
10
+ database: murlsh.db
9
11
  feed_file: atom.atom
10
12
  gravatar_size: 32
11
13
  js_files:
@@ -13,12 +15,12 @@ js_files:
13
15
  - js/jquery.jgrowl_compressed.js
14
16
  - js/twitter-text-1.3.1.js
15
17
  - js/js.js
16
- meta_tag_description: URLs found interesting by Matthew M. Boedicker
18
+ meta_tag_description:
17
19
  meta_tag_verify-v1:
18
20
  meta_tag_viewport: width=device-width,minimum-scale=1.0,maximum-scale=1.0
19
21
  num_posts_feed: 25
20
22
  num_posts_page: 25
21
- page_title: mmb url share
23
+ page_title: murlsh
22
24
  pubsubhubbub_hubs: []
23
25
 
24
26
  quick_search:
@@ -29,6 +31,9 @@ quick_search:
29
31
  video: hulu.com vimeo.com www.ted.com youtube.com
30
32
  wikipedia: wikipedia.org
31
33
  root_url: http://urls.matthewm.boedicker.org/
34
+ s3_bucket:
35
+ s3_id:
36
+ s3_secret:
32
37
  show_names: true
33
38
  thumbnail_max_side: 90
34
- user_agent: murlsh (http://github.com/mmb/murlsh)
39
+ user_agent: murlsh (https://github.com/mmb/murlsh)
@@ -0,0 +1,20 @@
1
+ class Init < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ create_table :urls do |t|
5
+ # t.integer :id
6
+ t.integer :content_length
7
+ t.string :content_type
8
+ t.string :email
9
+ t.string :name
10
+ t.timestamp :time
11
+ t.string :thumbnail_url
12
+ t.string :title
13
+ t.string :url
14
+ t.string :via
15
+ end
16
+
17
+ add_index :urls, :time
18
+ end
19
+
20
+ end
@@ -0,0 +1,78 @@
1
+ require 'uri'
2
+
3
+ require 'tinyatom'
4
+
5
+ require 'murlsh'
6
+
7
+ module Murlsh
8
+
9
+ # Atom feed builder.
10
+ class AtomBody
11
+ include Murlsh::FeedBody
12
+
13
+ # Atom feed builder.
14
+ def build
15
+ if defined?(@body)
16
+ @body
17
+ else
18
+ feed = TinyAtom::Feed.new(config.fetch('root_url'), feed_title,
19
+ feed_url, :hubs => config.fetch('pubsubhubbub_hubs', []).
20
+ map { |x| x['subscribe_url'] })
21
+
22
+ urls.each do |mu|
23
+ Murlsh::Plugin.hooks('url_display_pre') do |p|
24
+ p.run mu, req, config
25
+ end
26
+
27
+ options = {
28
+ :author_name => mu.name,
29
+ :summary => mu.title_stripped
30
+ }
31
+
32
+ if EnclosureContentTypes.include?(mu.content_type)
33
+ options.merge!(
34
+ :enclosure_type => mu.content_type,
35
+ :enclosure_href => mu.url,
36
+ :enclosure_title => mu.title
37
+ )
38
+ if mu.content_length
39
+ options.merge! :enclosure_length => mu.content_length
40
+ end
41
+ end
42
+
43
+ if mu.thumbnail_url
44
+ begin
45
+ # Add root url to relative urls.
46
+ tu = URI(mu.thumbnail_url)
47
+ abs_url = if tu.is_a?(URI::HTTP)
48
+ tu
49
+ else
50
+ URI.join config.fetch('root_url'), tu
51
+ end
52
+ options.merge! :media_thumbnail_url => abs_url
53
+ rescue URI::InvalidURIError
54
+ end
55
+ end
56
+
57
+ Murlsh::failproof do
58
+ if mu.via
59
+ options.merge!(
60
+ :via_type => 'text/html',
61
+ :via_href => mu.via,
62
+ :via_title => URI(mu.via).extend(Murlsh::URIDomain).domain
63
+ )
64
+ end
65
+ end
66
+
67
+ feed.add_entry mu.id, mu.title_stripped, mu.time, mu.url, options
68
+ end
69
+
70
+ @updated = feed.updated
71
+ @body = feed.make
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+
78
+ end