murlsh 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,3 +1,20 @@
1
+ 1.9.0
2
+ 2011-09-25
3
+
4
+ Do not strip trailing slashes from urls during normalization.
5
+
6
+ Add enclosures to JSON.
7
+
8
+ Support multiple enclosures per url that can be set by plugins.
9
+
10
+ Plugins for adding enclosures for YouTube and Vimeo urls.
11
+
12
+ Support builder version 3.
13
+
14
+ Update user agent sent when asking about urls to more recent browser.
15
+
16
+ Use "required" instead of "optional" attribute for form inputs.
17
+
1
18
  1.8.0
2
19
  2011-06-22
3
20
 
@@ -0,0 +1,32 @@
1
+ require 'murlsh'
2
+
3
+ class CreateEnclosures < ActiveRecord::Migration
4
+
5
+ def self.up
6
+ create_table :enclosures do |t|
7
+ t.integer :content_length
8
+ t.string :content_type
9
+ t.string :title
10
+ t.string :enclosure_url
11
+
12
+ t.references :url
13
+ end
14
+
15
+ add_index :enclosures, :url_id
16
+
17
+ # populate
18
+ require './plugins/add_pre_55_enclosure_self.rb'
19
+ require './plugins/add_pre_55_enclosure_vimeo.rb'
20
+ require './plugins/add_pre_55_enclosure_youtube.rb'
21
+
22
+ Murlsh::Url.find(:all).each do |u|
23
+ Murlsh::Plugin.hooks('add_pre') { |p| p.run u, {} }
24
+ u.save!
25
+ end
26
+ end
27
+
28
+ def self.down
29
+ drop_table :enclosures
30
+ end
31
+
32
+ end
@@ -29,15 +29,17 @@ module Murlsh
29
29
  :summary => mu.title_stripped
30
30
  }
31
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
32
+ options[:enclosures] = []
33
+ mu.enclosures.each do |e|
34
+ new_e = {
35
+ :enclosure_href => e.enclosure_url,
36
+ :enclosure_title => e.title_stripped,
37
+ :enclosure_type => e.content_type
38
+ }
39
+
40
+ new_e[:enclosure_length] = e.content_length if e.content_length
41
+
42
+ options[:enclosures] << new_e
41
43
  end
42
44
 
43
45
  if mu.thumbnail_url
@@ -0,0 +1,14 @@
1
+ require 'active_record'
2
+
3
+ module Murlsh
4
+
5
+ # Enclosure ActiveRecord.
6
+ class Enclosure < ActiveRecord::Base
7
+ belongs_to :url
8
+
9
+ # Title with whitespace compressed and leading and trailing whitespace
10
+ # stripped.
11
+ def title_stripped; title.to_s.strip.gsub(/\s+/, ' '); end
12
+ end
13
+
14
+ end
@@ -3,15 +3,6 @@ module Murlsh
3
3
  # Feed body mixin.
4
4
  module FeedBody
5
5
 
6
- # Content types to add an enclosure for.
7
- EnclosureContentTypes = %w{
8
- application/pdf
9
- audio/mpeg
10
- image/gif
11
- image/jpeg
12
- image/png
13
- }
14
-
15
6
  def initialize(config, req, feed_url, urls)
16
7
  @config, @req, @feed_url, @urls = config, req, feed_url, urls
17
8
  @updated = nil
@@ -33,6 +33,12 @@ module Murlsh
33
33
  h['thumbnail_url']).to_s
34
34
  end
35
35
 
36
+ h['enclosures'] = mu.enclosures.map do |e|
37
+ new_e = e.attributes.reject { |k,v| k == 'url_id' }
38
+ new_e['title'] = e.title_stripped
39
+ new_e
40
+ end
41
+
36
42
  h
37
43
  end
38
44
  @body = urls.to_json
data/lib/murlsh/markup.rb CHANGED
@@ -8,7 +8,7 @@ module Murlsh
8
8
  # Options:
9
9
  # * :prefix - prefix to append to all script urls
10
10
  def javascript(sources, options={})
11
- Array(sources).each do |src|
11
+ ::Kernel::Array(sources).each do |src|
12
12
  script '', :type => 'text/javascript',
13
13
  :src => "#{options[:prefix]}#{src}"
14
14
  end
@@ -50,7 +50,7 @@ module Murlsh
50
50
  # * :media - optional media attribute
51
51
  # * :prefix - prepended to all CSS urls
52
52
  def css(hrefs, options={})
53
- Array(hrefs).each do |href|
53
+ ::Kernel::Array(hrefs).each do |href|
54
54
  attrs = {
55
55
  :href => "#{options[:prefix]}#{href}",
56
56
  :rel => 'stylesheet',
@@ -69,7 +69,7 @@ module Murlsh
69
69
  def form_input(options)
70
70
  if options[:id]
71
71
  if options[:label]
72
- label_class = options[:optional] ? 'optional' : 'required'
72
+ label_class = options[:required] ? 'required' : 'optional'
73
73
  label options[:label], :for => options[:id], :class => label_class
74
74
  end
75
75
  options[:name] ||= options[:id]
@@ -29,11 +29,12 @@ module Murlsh
29
29
  i.link = mu.url
30
30
  i.date = mu.time
31
31
 
32
- if EnclosureContentTypes.include? mu.content_type
33
- i.enclosure.url = mu.url
34
- i.enclosure.type = mu.content_type
35
- i.enclosure.length = mu.content_length
32
+ mu.enclosures.first(1).each do |e|
33
+ i.enclosure.url = e.enclosure_url
34
+ i.enclosure.type = e.content_type
35
+ i.enclosure.length = e.content_length
36
36
  end
37
+
37
38
  end
38
39
  end
39
40
 
@@ -93,7 +93,7 @@ module Murlsh
93
93
  def default_headers
94
94
  result = {
95
95
  'User-Agent' =>
96
- 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624',
96
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.126 Safari/535.1',
97
97
  }
98
98
  if host.to_s[/^www\.nytimes\.com/]
99
99
  result['Referer'] = 'http://news.google.com/'
data/lib/murlsh/url.rb CHANGED
@@ -6,6 +6,7 @@ module Murlsh
6
6
 
7
7
  # URL ActiveRecord.
8
8
  class Url < ActiveRecord::Base
9
+ has_many :enclosures
9
10
  validates_format_of :url, :with => URI.regexp
10
11
 
11
12
  # Get the title of this url.
@@ -21,7 +22,7 @@ module Murlsh
21
22
 
22
23
  # Title with whitespace compressed and leading and trailing whitespace
23
24
  # stripped.
24
- def title_stripped; title.strip.gsub(/\s+/, ' '); end
25
+ def title_stripped; title.to_s.strip.gsub(/\s+/, ' '); end
25
26
 
26
27
  # Return true if this url has the same author as another url.
27
28
  def same_author?(other)
@@ -5,7 +5,7 @@ module Murlsh
5
5
 
6
6
  # Url list page builder.
7
7
  class UrlBody < Builder::XmlMarkup
8
- include Murlsh::Markup
8
+ include ::Murlsh::Markup
9
9
 
10
10
  def initialize(config, req, result_set, content_type='text/html')
11
11
  @config, @req, @result_set, @content_type = config, req, result_set,
@@ -20,7 +20,7 @@ module Murlsh
20
20
  if page.to_i >= 1
21
21
  query = @req.params.dup
22
22
  query['p'] = page
23
- Murlsh.build_query(query)
23
+ ::Murlsh.build_query(query)
24
24
  end
25
25
  end
26
26
 
@@ -50,13 +50,13 @@ module Murlsh
50
50
  last = nil
51
51
 
52
52
  @result_set.results.each do |mu|
53
- Murlsh::Plugin.hooks('url_display_pre') do |p|
53
+ ::Murlsh::Plugin.hooks('url_display_pre') do |p|
54
54
  p.run mu, @req, @config
55
55
  end
56
56
 
57
57
  li(:id => "liu#{mu.id}") {
58
58
  unless mu.same_author?(last)
59
- avatar_url = Murlsh::Plugin.hooks('avatar').inject(
59
+ avatar_url = ::Murlsh::Plugin.hooks('avatar').inject(
60
60
  nil) do |url_so_far,plugin|
61
61
  plugin.run url_so_far, mu, @config
62
62
  end
@@ -74,7 +74,7 @@ module Murlsh
74
74
 
75
75
  a mu.title_stripped, :href => mu.url, :class => 'm'
76
76
 
77
- Murlsh::Plugin.hooks('url_display_add') do |p|
77
+ ::Murlsh::Plugin.hooks('url_display_add') do |p|
78
78
  p.run self, mu, @config
79
79
  end
80
80
 
@@ -154,7 +154,7 @@ module Murlsh
154
154
  order += (@config['quick_search'].keys - order).sort
155
155
  order.each do |k|
156
156
  if v = @config['quick_search'][k]
157
- a "/#{k}", :href => "?q=#{URI.escape(v)}" ; text! ' '
157
+ a "/#{k}", :href => "?q=#{::URI.escape(v)}" ; text! ' '
158
158
  end
159
159
  end
160
160
  }
@@ -188,18 +188,15 @@ module Murlsh
188
188
  def add_form
189
189
  form(:action => 'url', :method => 'post') {
190
190
  fieldset(:id => 'add') {
191
- self.p { form_input :id => 'url', :label => 'Add URL', :size => 32 }
192
191
  self.p {
193
- form_input :id => 'title', :label => 'Title', :size => 32,
194
- :optional => true
195
- }
196
- self.p {
197
- form_input :id => 'via', :label => 'Via', :size => 32,
198
- :optional => true
192
+ form_input :id => 'url', :label => 'Add URL', :size => 32,
193
+ :required => ''
199
194
  }
195
+ self.p { form_input :id => 'title', :label => 'Title', :size => 32 }
196
+ self.p { form_input :id => 'via', :label => 'Via', :size => 32 }
200
197
  self.p {
201
198
  form_input :type => 'password', :id => 'auth', :label => 'Password',
202
- :size => 16
199
+ :size => 16, :required => ''
203
200
  form_input :id => 'submit', :type => 'button', :value => 'Add'
204
201
  }
205
202
  }
@@ -1,3 +1,3 @@
1
1
  module Murlsh
2
- VERSION = '1.8.0'
2
+ VERSION = '1.9.0'
3
3
  end
data/lib/murlsh.rb CHANGED
@@ -11,6 +11,7 @@ require 'murlsh/delicious_parse'
11
11
  require 'murlsh/dispatch'
12
12
  require 'murlsh/doc'
13
13
  require 'murlsh/etag_add_encoding'
14
+ require 'murlsh/enclosure'
14
15
  require 'murlsh/failproof'
15
16
  require 'murlsh/far_future_expires'
16
17
  require 'murlsh/feed_body'
@@ -4,26 +4,49 @@ require 'postrank-uri'
4
4
 
5
5
  require 'murlsh'
6
6
 
7
+ # Patch PostRank::URI.normalize to not strip trailing slashes from the path.
8
+ module PostRank
9
+
10
+ module URI
11
+
12
+ module_function
13
+
14
+ def normalize(uri, opts = {})
15
+ u = parse(uri, opts)
16
+ u.path = u.path.squeeze('/')
17
+ # u.path = u.path.chomp('/') if u.path.size != 1
18
+ u.query = nil if u.query && u.query.empty?
19
+ u.fragment = nil
20
+ u
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
7
27
  module Murlsh
8
28
 
9
- # Canonicalize and clean urls with postrank-uri.
10
- #
11
- # See https://github.com/postrank-labs/postrank-uri
29
+ # Canonicalize and clean urls.
30
+
12
31
  class AddPre35UrlClean < Plugin
13
32
 
14
33
  @hook = 'add_pre'
15
34
 
16
35
  def self.run(url, config)
17
- url.url = PostRank::URI.clean(url.url) if cleanable?(url.url)
18
- url.via = PostRank::URI.clean(url.via) if cleanable?(url.via)
36
+ Murlsh::failproof { url.url = clean(url.url) if cleanable?(url.url) }
37
+ Murlsh::failproof { url.via = clean(url.via) if cleanable?(url.via) }
19
38
  end
20
39
 
21
- # Return true if the url can be cleaned by postrank-uri.
40
+ # Canonicalize and clean a url using PostRank::URI.clean.
22
41
  #
23
- # Postrank::URI.clean only works on https or https urls.
24
- def self.cleanable?(url)
25
- Murlsh::failproof { URI(url).scheme.to_s.match(/^https?$/i) }
26
- end
42
+ # PostRank::URI.normalize is patched to not strip trailing slashes from
43
+ # the path (see above).
44
+ #
45
+ # See https://github.com/postrank-labs/postrank-uri
46
+ def self.clean(url); PostRank::URI.clean(url); end
47
+
48
+ # Return true if the url can be cleaned (is http or https).
49
+ def self.cleanable?(url); URI(url).scheme.to_s.match(/^https?$/i); end
27
50
 
28
51
  end
29
52
 
@@ -0,0 +1,31 @@
1
+ require 'murlsh'
2
+
3
+ module Murlsh
4
+
5
+ # Create enclosures for content types that can directly become enclosures.
6
+ class AddPre55EnclosureSelf < Plugin
7
+
8
+ @hook = 'add_pre'
9
+
10
+ # Content types that can be enclosures.
11
+ ContentTypes = %w{
12
+ application/pdf
13
+ audio/mpeg
14
+ image/gif
15
+ image/jpeg
16
+ image/png
17
+ }
18
+
19
+ def self.run(url, config)
20
+ if ContentTypes.include?(url.content_type)
21
+ url.enclosures.build(
22
+ :content_length => url.content_length,
23
+ :title => url.title,
24
+ :content_type => url.content_type,
25
+ :enclosure_url => url.url)
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,24 @@
1
+ require 'murlsh'
2
+
3
+ module Murlsh
4
+
5
+ # Create video enclosures for Vimeo urls.
6
+ class AddPre55EnclosureVimeo < Plugin
7
+
8
+ @hook = 'add_pre'
9
+
10
+ VimeoRe = %r{^http://(?:www\.)?vimeo\.com/(\d+)$}i
11
+
12
+ def self.run(url, config)
13
+ if match = VimeoRe.match(url.url)
14
+ url.enclosures.build(
15
+ :title => url.title,
16
+ :content_type => 'application/x-shockwave-flash',
17
+ :enclosure_url =>
18
+ "http://vimeo.com/moogaloop.swf?clip_id=#{match[1]}")
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'murlsh'
2
+
3
+ module Murlsh
4
+
5
+ # Create video enclosures for YouTube urls.
6
+ class AddPre55EnclosureYoutube < Plugin
7
+
8
+ @hook = 'add_pre'
9
+
10
+ YoutubeRe =
11
+ %r{^http://(?:(?:www|uk)\.)?youtube\.com/watch\?v=([\w\-]+)(?:&|$)}i
12
+
13
+ def self.run(url, config)
14
+ if match = YoutubeRe.match(url.url)
15
+ url.enclosures.build(
16
+ :title => url.title,
17
+ :content_type => 'application/x-shockwave-flash',
18
+ :enclosure_url => "http://www.youtube.com/v/#{match[1]}.swf")
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: murlsh
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
4
+ hash: 51
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 8
8
+ - 9
9
9
  - 0
10
- version: 1.8.0
10
+ version: 1.9.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthew M. Boedicker
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-22 00:00:00 -04:00
18
+ date: 2011-09-25 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -377,6 +377,7 @@ files:
377
377
  - config.yaml
378
378
  - config/README
379
379
  - db/migrate/20110213023123_init.rb
380
+ - db/migrate/20110906003222_create_enclosures.rb
380
381
  - lib/murlsh.rb
381
382
  - lib/murlsh/ask.rb
382
383
  - lib/murlsh/atom_body.rb
@@ -388,6 +389,7 @@ files:
388
389
  - lib/murlsh/delicious_parse.rb
389
390
  - lib/murlsh/dispatch.rb
390
391
  - lib/murlsh/doc.rb
392
+ - lib/murlsh/enclosure.rb
391
393
  - lib/murlsh/etag_add_encoding.rb
392
394
  - lib/murlsh/failproof.rb
393
395
  - lib/murlsh/far_future_expires.rb
@@ -433,6 +435,9 @@ files:
433
435
  - plugins/add_pre_50_lookup_content_type_title.rb
434
436
  - plugins/add_pre_50_media_thumbnail.rb
435
437
  - plugins/add_pre_50_open_graph_image.rb
438
+ - plugins/add_pre_55_enclosure_self.rb
439
+ - plugins/add_pre_55_enclosure_vimeo.rb
440
+ - plugins/add_pre_55_enclosure_youtube.rb
436
441
  - plugins/add_pre_55_open_graph_title.rb
437
442
  - plugins/add_pre_60_github_title.rb
438
443
  - plugins/add_pre_60_imgur.rb