murlsh 1.4.1 → 1.5.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.
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
@@ -1,5 +1,3 @@
1
- require 'cgi'
2
-
3
1
  require 'murlsh'
4
2
 
5
3
  module Murlsh
@@ -9,20 +7,17 @@ module Murlsh
9
7
 
10
8
  @hook = 'add_pre'
11
9
 
12
- StorageDir = File.join(File.dirname(__FILE__), '..', 'public', 'img',
13
- 'thumb')
14
-
15
10
  def self.run(url, config)
16
11
  if url.thumbnail_url
17
12
  Murlsh::failproof do
18
- thumb_storage = Murlsh::ImgStore.new(StorageDir,
19
- :user_agent => config['user_agent'])
13
+ thumb_storage = Murlsh::ImgStore.new(config)
20
14
 
21
- stored_filename = thumb_storage.store_url(url.thumbnail_url) do |i|
15
+ stored_url = thumb_storage.store_url(url.thumbnail_url) do |i|
22
16
  max_side = config.fetch('thumbnail_max_side', 90)
23
17
  i.extend(Murlsh::ImageList).resize_down!(max_side)
24
18
  end
25
- url.thumbnail_url = "img/thumb/#{CGI.escape(stored_filename)}"
19
+
20
+ url.thumbnail_url = stored_url if stored_url
26
21
  end
27
22
  end
28
23
  end
@@ -1,5 +1,3 @@
1
- require 'cgi'
2
-
3
1
  require 'murlsh'
4
2
 
5
3
  module Murlsh
@@ -9,9 +7,6 @@ module Murlsh
9
7
 
10
8
  @hook = 'add_pre'
11
9
 
12
- StorageDir = File.join(File.dirname(__FILE__), '..', 'public', 'img',
13
- 'thumb')
14
-
15
10
  def self.run(url, config)
16
11
  if not url.thumbnail_url and url.ask.doc
17
12
  url.ask.doc.xpath_search(%w{
@@ -20,14 +15,14 @@ module Murlsh
20
15
  }) do |node|
21
16
  if node and not node['href'].to_s.empty?
22
17
  Murlsh::failproof do
23
- thumb_storage = Murlsh::ImgStore.new(StorageDir,
24
- :user_agent => config['user_agent'])
18
+ thumb_storage = Murlsh::ImgStore.new(config)
25
19
 
26
- stored_filename = thumb_storage.store_url(node['href']) do |i|
20
+ stored_url = thumb_storage.store_url(node['href']) do |i|
27
21
  max_side = config.fetch('thumbnail_max_side', 90)
28
22
  i.extend(Murlsh::ImageList).resize_down!(max_side)
29
23
  end
30
- url.thumbnail_url = "img/thumb/#{CGI.escape(stored_filename)}"
24
+
25
+ url.thumbnail_url = stored_url if stored_url
31
26
  end
32
27
  end
33
28
  end
@@ -1,4 +1,3 @@
1
- require 'cgi'
2
1
  require 'uri'
3
2
 
4
3
  require 'murlsh'
@@ -10,9 +9,6 @@ module Murlsh
10
9
 
11
10
  @hook = 'add_pre'
12
11
 
13
- StorageDir = File.join(File.dirname(__FILE__), '..', 'public', 'img',
14
- 'thumb')
15
-
16
12
  def self.run(url, config)
17
13
  if not url.thumbnail_url and url.ask.doc
18
14
  url.ask.doc.xpath_search("//meta[@property='og:image']") do |node|
@@ -23,14 +19,14 @@ module Murlsh
23
19
  if og_image_url[%r{^//}]
24
20
  og_image_url = "#{URI(url.url).scheme}:#{og_image_url}"
25
21
  end
26
- thumb_storage = Murlsh::ImgStore.new(StorageDir,
27
- :user_agent => config['user_agent'])
22
+ thumb_storage = Murlsh::ImgStore.new(config)
28
23
 
29
- stored_filename = thumb_storage.store_url(og_image_url) do |i|
24
+ stored_url = thumb_storage.store_url(og_image_url) do |i|
30
25
  max_side = config.fetch('thumbnail_max_side', 90)
31
26
  i.extend(Murlsh::ImageList).resize_down!(max_side)
32
27
  end
33
- url.thumbnail_url = "img/thumb/#{CGI.escape(stored_filename)}"
28
+
29
+ url.thumbnail_url = stored_url if stored_url
34
30
  end
35
31
  end
36
32
  end
@@ -10,7 +10,7 @@ module Murlsh
10
10
 
11
11
  @hook = 'add_pre'
12
12
 
13
- GithubRe = %r{^https?://github\.com/\w+/[\w.-]+$}i
13
+ GithubRe = %r{^https?://github\.com/\w+/[\w.-]+/?$}i
14
14
 
15
15
  def self.run(url, config)
16
16
  if not url.user_supplied_title? and url.url.to_s[GithubRe]
@@ -1,5 +1,3 @@
1
- require 'cgi'
2
-
3
1
  require 'plumnailer'
4
2
 
5
3
  require 'murlsh'
@@ -11,9 +9,6 @@ module Murlsh
11
9
 
12
10
  @hook = 'add_pre'
13
11
 
14
- StorageDir = File.join(File.dirname(__FILE__), '..', 'public', 'img',
15
- 'thumb')
16
-
17
12
  def self.run(url, config)
18
13
  if not url.thumbnail_url and url.content_type and
19
14
  url.content_type[Murlsh::UriAsk::HtmlContentTypeRe]
@@ -25,10 +20,10 @@ module Murlsh
25
20
  max_side = config.fetch('thumbnail_max_side', 90)
26
21
  choice.extend(Murlsh::ImageList).resize_down!(max_side)
27
22
 
28
- thumb_storage = Murlsh::ImgStore.new(StorageDir)
23
+ thumb_storage = Murlsh::ImgStore.new(config)
29
24
 
30
- stored_filename = thumb_storage.store_img(choice)
31
- url.thumbnail_url = "img/thumb/#{CGI.escape(stored_filename)}"
25
+ stored_url = thumb_storage.store_img(choice)
26
+ url.thumbnail_url = stored_url if stored_url
32
27
  end
33
28
  end
34
29
  end
@@ -1,5 +1,3 @@
1
- require 'cgi'
2
-
3
1
  require 'murlsh'
4
2
 
5
3
  module Murlsh
@@ -9,9 +7,6 @@ module Murlsh
9
7
 
10
8
  @hook = 'add_pre'
11
9
 
12
- StorageDir = File.join(File.dirname(__FILE__), '..', 'public', 'img',
13
- 'thumb')
14
-
15
10
  ImageContentType = %w{
16
11
  image/gif
17
12
  image/jpeg
@@ -22,14 +17,14 @@ module Murlsh
22
17
  if not url.thumbnail_url and url.content_type and
23
18
  ImageContentType.include?(url.content_type)
24
19
  Murlsh::failproof do
25
- thumb_storage = Murlsh::ImgStore.new(StorageDir,
26
- :user_agent => config['user_agent'])
20
+ thumb_storage = Murlsh::ImgStore.new(config)
27
21
 
28
- stored_filename = thumb_storage.store_url(url.url) do |i|
22
+ stored_url = thumb_storage.store_url(url.url) do |i|
29
23
  max_side = config.fetch('thumbnail_max_side', 90)
30
24
  i.extend(Murlsh::ImageList).resize_down!(max_side)
31
25
  end
32
- url.thumbnail_url = "img/thumb/#{CGI.escape(stored_filename)}"
26
+
27
+ url.thumbnail_url = stored_url if stored_url
33
28
  end
34
29
  end
35
30
  end
@@ -13,7 +13,8 @@ module Murlsh
13
13
  if url.email and not url.email.empty? and
14
14
  (gravatar_size = config.fetch('gravatar_size', 0)) > 0
15
15
  query = { :s => gravatar_size }
16
- URI.join('http://www.gravatar.com/avatar/', url.email, Murlsh::build_query(query))
16
+ URI.join('http://www.gravatar.com/avatar/', url.email,
17
+ Murlsh::build_query(query))
17
18
  end
18
19
  end
19
20
 
@@ -0,0 +1,40 @@
1
+ require 'time'
2
+
3
+ require 'aws/s3'
4
+
5
+ module Murlsh
6
+
7
+ # Store assets in Amazon S3.
8
+ #
9
+ # Depends on 's3_id', 's3_secret', and 's3_bucket' in config.
10
+ class StoreAsset40S3 < Plugin
11
+
12
+ @hook = 'store_asset'
13
+
14
+ def self.run(name, data, config)
15
+ if !config['s3_id'].to_s.empty? and
16
+ !config['s3_secret'].to_s.empty? and
17
+ !config['s3_bucket'].to_s.empty?
18
+ AWS::S3::Base.establish_connection!(
19
+ :access_key_id => config['s3_id'],
20
+ :secret_access_key => config['s3_secret']
21
+ )
22
+
23
+ bucket = begin
24
+ AWS::S3::Bucket.find config['s3_bucket']
25
+ rescue AWS::S3::NoSuchBucket
26
+ AWS::S3::Bucket.create config['s3_bucket'], :access => :public_read
27
+ end
28
+
29
+ AWS::S3::S3Object.store name, data, bucket.name,
30
+ :access => :public_read,
31
+ # 100 years
32
+ :expires => (Time.now + (31536000000)).httpdate
33
+
34
+ AWS::S3::S3Object.url_for(name, bucket.name, :authenticated => false)
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,22 @@
1
+ require 'murlsh'
2
+
3
+ module Murlsh
4
+
5
+ # Store assets on the local filesystem in the public directory.
6
+ class StoreAsset50Local < Plugin
7
+
8
+ @hook = 'store_asset'
9
+
10
+ def self.run(name, data, config)
11
+ # break apart and rejoin to use os path separator
12
+ name_parts = name.split('/')
13
+ local_path = File.join('public', name_parts)
14
+
15
+ Murlsh::openlock(local_path, 'w') { |fout| fout.write data }
16
+
17
+ name
18
+ end
19
+
20
+ end
21
+
22
+ end
data/public/js/js.js CHANGED
@@ -9,8 +9,6 @@ var Murlsh = function ($, navigator, window, twtter) {
9
9
  /^http:\/\/img\d+\.imageshack\.us\/img\d+\/\d+\/\w+\.(?:jpe?g|gif|png)$/i,
10
10
  imgur :
11
11
  /^http:\/\/(?:i\.)?imgur\.com\/[a-z\d]+\.(?:jpe?g|gif|png)$/i,
12
- s3 :
13
- /^http:\/\/static\.mmb\.s3\.amazonaws\.com\/[\w\-]+\.(jpe?g|gif|pdf|png)$/i,
14
12
  twitter :
15
13
  /^https?:\/\/twitter\.com\/\w+\/status(?:es)?\/\d+$/i,
16
14
  vimeo :
@@ -119,11 +117,6 @@ var Murlsh = function ($, navigator, window, twtter) {
119
117
 
120
118
  if (match.imageshack || match.imgur) {
121
119
  setupClickHandler(thisA.siblings('img'), 'href', href, imgClick);
122
- } else if (match.s3) {
123
- if (!(match.s3[1].match(/^pdf$/i))) {
124
- setupClickHandler(thisA.siblings('img'), 'href', href,
125
- imgClick);
126
- }
127
120
  } else if (match.twitter) {
128
121
  thisA.siblings('img').addClass('twitter');
129
122
  tweetMatch = /^(@[0-9a-z_]+?): (.+)$/i.exec(thisA.text());
data/spec/auth_spec.rb CHANGED
@@ -30,4 +30,11 @@ describe Murlsh::Auth do
30
30
  @a.auth('not there').should be_nil
31
31
  end
32
32
 
33
+ it 'should be able to find user by email address' do
34
+ @a.by_email('test1@test.com').should == {
35
+ :name => 'test1',
36
+ :email => Digest::MD5.hexdigest('test1@test.com')
37
+ }
38
+ end
39
+
33
40
  end
@@ -0,0 +1,49 @@
1
+ require 'tempfile'
2
+
3
+ require 'murlsh'
4
+
5
+ describe Murlsh do
6
+
7
+ describe :cat_files do
8
+
9
+ context 'when all files are there' do
10
+
11
+ before do
12
+ @f1 = Tempfile.new('f1')
13
+ (1..2).each { |i| @f1.write "#{i}\n" }
14
+ @f1.close
15
+
16
+ @f2 = Tempfile.new('f2')
17
+ (1..3).each { |i| @f2.write "#{i}\n" }
18
+ @f2.close
19
+ end
20
+
21
+ after do
22
+ @f1.unlink
23
+ @f2.unlink
24
+ end
25
+
26
+ it 'should cat the files together and return the result' do
27
+ Murlsh.cat_files([@f1.path, @f2.path]).should == <<eos
28
+ 1
29
+ 2
30
+ 1
31
+ 2
32
+ 3
33
+ eos
34
+ end
35
+
36
+ end
37
+
38
+ context 'when one or more files are missing' do
39
+
40
+ it 'should raise no such file or directory' do
41
+ lambda { Murlsh.cat_files(['does_not_exist']) }.should raise_error(
42
+ Errno::ENOENT)
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -7,12 +7,28 @@ require 'RMagick'
7
7
 
8
8
  require 'murlsh'
9
9
 
10
+ module Murlsh
11
+
12
+ class StoreAsset50Test < Plugin
13
+
14
+ @hook = 'store_asset'
15
+
16
+ def self.run(name, data, config)
17
+ local_path = File.join(Dir::tmpdir, 'img_store_test', name)
18
+ FileUtils.mkdir_p(File.dirname(local_path))
19
+ Murlsh::openlock(local_path, 'w') { |fout| fout.write data }
20
+ name
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
10
27
  describe Murlsh::ImgStore do
11
28
 
12
29
  before(:all) do
13
30
  @thumb_dir = File.join(Dir::tmpdir, 'img_store_test')
14
- FileUtils.mkdir_p @thumb_dir
15
- @img_store = Murlsh::ImgStore.new(@thumb_dir)
31
+ @img_store = Murlsh::ImgStore.new({})
16
32
  end
17
33
 
18
34
  describe :store_url do
@@ -22,13 +38,13 @@ describe Murlsh::ImgStore do
22
38
  before(:all) do
23
39
  image_url =
24
40
  'http://static.mmb.s3.amazonaws.com/2010_10_8_bacon_pancakes.jpg'
25
- @local_file = @img_store.store_url(image_url)
26
- @local_path = File.join(@thumb_dir, @local_file)
41
+ @stored_url = @img_store.store_url(image_url)
42
+ @local_path = File.join(@thumb_dir, @stored_url)
27
43
  end
28
44
 
29
45
  it 'should be named with the md5 sum of its contents' do
30
46
  md5 = Digest::MD5.file(@local_path).hexdigest
31
- @local_file.should == "#{md5}.jpg"
47
+ @stored_url.should == "img/thumb/#{md5}.jpg"
32
48
  end
33
49
 
34
50
  end
@@ -54,13 +70,13 @@ describe Murlsh::ImgStore do
54
70
  'http://static.mmb.s3.amazonaws.com/2010_10_8_bacon_pancakes.jpg') do |f|
55
71
  f.read
56
72
  end
57
- @local_file = @img_store.store_img_data(img_data)
58
- @local_path = File.join(@thumb_dir, @local_file)
73
+ @stored_url = @img_store.store_img_data(img_data)
74
+ @local_path = File.join(@thumb_dir, @stored_url)
59
75
  end
60
76
 
61
77
  it 'should be named with the md5 sum of its contents' do
62
78
  md5 = Digest::MD5.file(@local_path).hexdigest
63
- @local_file.should == "#{md5}.jpg"
79
+ @stored_url.should == "img/thumb/#{md5}.jpg"
64
80
  end
65
81
 
66
82
  end