muri 0.0.13 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -8,7 +8,7 @@ MURI Currently supports:
8
8
  * Vimeo (single videos and albums)
9
9
  ** "API documentation":http://vimeo.com/api/docs/simple-api
10
10
  * Flickr (single images and sets)
11
- ** "API documentation":http://www.flickr.com/services/api/
11
+ ** "API documentation":http://www.flickr.com/services/api/ or "[2]":http://developer.yahoo.com/flickr/
12
12
  * Imageshack
13
13
  * Photobucket
14
14
  ** "API documentation":http://photobucket.com/developer/documentation
@@ -41,10 +41,10 @@ Assuming the URI was successfully parsed (thus @a.valid? == true@), all media ty
41
41
 
42
42
  <pre>
43
43
  <code>
44
- a.service # 'Youtube'
45
- a.media_id # 'blahblahblah'
46
- a.original_url # 'http://www.youtube.com/watch?v=blahblahblah&feature=rec-LGOUT-exp_fresh+div-1r-1-HM'
47
- a.uri # URI object for 'http://www.youtube.com/watch?v=blahblahblah&feature=rec-LGOUT-exp_fresh+div-1r-1-HM'
44
+ a.media_service # 'Youtube'
45
+ a.media_id # 'blahblahblah'
46
+ a.media_original_url # 'http://www.youtube.com/watch?v=blahblahblah&feature=rec-LGOUT-exp_fresh+div-1r-1-HM'
47
+ a.media_uri # URI object for 'http://www.youtube.com/watch?v=blahblahblah&feature=rec-LGOUT-exp_fresh+div-1r-1-HM'
48
48
  </code>
49
49
  </pre>
50
50
 
@@ -53,7 +53,7 @@ Assuming the URI was successfully parsed (thus @a.valid? == true@), all media ty
53
53
  * All but Imageshack have a @media_api_id@, which is the ID which can be used in API calls to the related services. Typically the same as @media_id@.
54
54
 
55
55
  <pre>
56
- <code>
56
+ <code>
57
57
  a.media_api_id # 'blahblahblah'
58
58
  </code>
59
59
  </pre>
@@ -76,7 +76,7 @@ d
76
76
 
77
77
  <pre>
78
78
  <code>
79
- a.website # 'http://www.youtube.com/watch?v=blahblahblah'
79
+ a.media_website # 'http://www.youtube.com/watch?v=blahblahblah'
80
80
  </code>
81
81
  </pre>
82
82
 
@@ -84,7 +84,7 @@ d
84
84
 
85
85
  <pre>
86
86
  <code>
87
- a.content_type # 'jpg' (Content Type also for Imageshack and Photobucket)
87
+ a.media_content_type # 'jpg' (Content Type also for Imageshack and Photobucket)
88
88
  </code>
89
89
  </pre>
90
90
 
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :major: 0
2
+ :major: 1
3
3
  :minor: 0
4
- :patch: 13
4
+ :patch: 0
data/lib/muri/base.rb CHANGED
@@ -1,112 +1,92 @@
1
- require 'uri'
2
1
  class Muri
3
2
 
3
+ attr_reader :uri, :errors
4
+
4
5
  # NoParser raised if no parser is found for URI
5
6
  class NoParser < StandardError; end
6
-
7
- # UnsupportedURI raised if parser is found, but URI path does not
7
+
8
+ # UnsupportedURI raised if parser is found, but URI path does not
8
9
  # match accepted formats
9
10
  class UnsupportedURI < ArgumentError; end
10
-
11
- PARSERS = {}
12
-
13
- include Filter::Youtube
14
- include Filter::Flickr
15
- include Filter::Vimeo
16
- include Filter::Imageshack
17
- include Filter::Photobucket
18
- include Filter::Facebook
19
- include Filter::Twitpic
11
+
12
+ PARSERS = { }
13
+
14
+ # Defines is_#{service}? and is_#{service type constant}? methods, and sets service name constnat
15
+ ['Youtube', 'Flickr', 'Vimeo', 'Imageshack', 'Photobucket', 'Facebook', 'Twitpic'].each do |filter|
16
+ eval "include Filter::#{filter}"
17
+ is_service = "is_#{filter.downcase}?"
18
+ define_method(is_service) { self.media_service == filter }
19
+ self.constants.reject { |c| c !~ /^#{filter.upcase}/ }.each do |exp|
20
+ define_method("is_#{exp.downcase}?") { self.media_api_type == eval(exp) && eval("self.#{is_service}") }
21
+ end
22
+ const_set "#{filter.upcase}_SERVICE_NAME", "#{filter}"
23
+ end
20
24
 
21
25
  def self.parse(url)
22
26
  self.new(url)
23
27
  end
24
-
25
- def initialize(url)
26
- @info = { }
27
- _parse(url)
28
- end
29
28
 
30
- def to_yaml
31
- @info.to_yaml
29
+ # Show a list of the available parsers
30
+ def self.parsers
31
+ PARSERS.keys
32
32
  end
33
33
 
34
- def to_s
35
- @info.to_s
34
+ def initialize(url)
35
+ @info = { }
36
+ _parse(url)
36
37
  end
37
38
 
39
+ # Determine if Muri object is valid (errors mean not valid)
38
40
  def valid?
39
- @info[:media_id].nil? ? false : true
41
+ self.errors.nil?
40
42
  end
41
43
 
42
- # Taken from uri/generic.rb
43
- @@to_s = Kernel.instance_method(:to_s)
44
- def inspect
45
- @@to_s.bind(self).call.sub!(/>\z/) {" URL:#{self.original_url}>"}
44
+ def to_s
45
+ @info.to_s
46
46
  end
47
-
48
- def parsers
49
- PARSERS.keys
47
+
48
+ # 'Borrowed' from uri/generic.rb
49
+ def inspect
50
+ Kernel.instance_method(:to_s).bind(self).call.sub!(/>\z/) {" URL:#{self.uri.to_s}>"}
50
51
  end
51
-
52
+
52
53
  private
54
+ attr_writer :uri, :errors
55
+
56
+ def self.determine_feed_parser(uri)
57
+ PARSERS.keys.detect {|klass| klass.parsable?(uri)}
58
+ end
53
59
 
54
60
  def _parse(raw_url)
55
61
  begin
56
- @url = URI.parse(raw_url)
57
- if @url.scheme.nil?
62
+ self.uri = URI.parse(raw_url)
63
+ if self.uri.scheme.nil?
58
64
  raw_url = "http://#{raw_url}"
59
- @url = URI.parse(raw_url)
65
+ self.uri = URI.parse(raw_url)
60
66
  end
61
- if parser = determine_feed_parser
62
- @info[:uri] = @url
63
- @info[:original_url] = raw_url
67
+ if parser = Muri.determine_feed_parser(self.uri)
64
68
  send(PARSERS[parser])
65
69
  else
66
70
  raise NoParser
67
71
  end
68
72
  rescue NoParser, UnsupportedURI, URI::BadURIError, URI::InvalidURIError => e
69
- @info[:errors] = "#{e.class}"
73
+ self.errors = "#{e.class}"
70
74
  end
71
75
  end
72
-
73
- def determine_feed_parser
74
- PARSERS.keys.detect {|klass| klass.parsable?(@url)}
75
- end
76
-
77
- def method_missing(func, args = nil)
78
- @info[func.to_sym].nil? ? nil : @info[func.to_sym]
79
- end
80
-
81
- protected
82
-
83
- #used by flickr. Ported from PHP.
84
- def self.decode58(str)
85
- decoded = 0
86
- multi = 1
87
- alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
88
- while str.length > 0
89
- digit = str[(str.length - 1),1]
90
- decoded += multi * alphabet.index(digit)
91
- multi = multi * alphabet.length
92
- str.chop!
76
+
77
+ def method_missing(method, *arguments, &block)
78
+ if method.to_s =~ /^media_(.+)/
79
+ process_option_method(method, *arguments)
80
+ else
81
+ super
93
82
  end
94
-
95
- decoded
96
83
  end
97
-
98
- #used by flickr. Ported from PHP.
99
- def self.encode58(str)
100
- alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
101
- base_count = alphabet.length
102
- encoded = ''
103
- while str >= base_count
104
- div = str / base_count
105
- mod = (str-(base_count * div))
106
- encoded = alphabet[mod,1] + encoded
107
- str = div
84
+
85
+ def process_option_method(method, *arguments)
86
+ if method.to_s =~ /^media_(.+)=/
87
+ @info[$1.to_sym] = arguments.first
88
+ elsif method.to_s =~ /^media_(.+)/
89
+ @info[$1.to_sym]
108
90
  end
109
- encoded = (alphabet[str,1] + encoded) if str
110
- encoded
111
91
  end
112
92
  end
data/lib/muri/filter.rb CHANGED
@@ -0,0 +1,13 @@
1
+ class Muri
2
+
3
+ protected
4
+
5
+ def self.param_parse(query)
6
+ return { } if query.nil?
7
+ params_flat = { }
8
+ params = CGI::parse(query)
9
+ params.each {|k,v| params_flat[k] = v.first}
10
+ params_flat
11
+ end
12
+
13
+ end
@@ -1,68 +1,66 @@
1
- require 'cgi'
2
1
  class Muri
3
2
  module Filter
4
3
  module Facebook
5
-
4
+
5
+ private
6
6
  FACEBOOK_PHOTO = "photo"
7
7
  #FACEBOOK_VIDEO = "video"
8
8
  FACEBOOK_ALBUM = "album"
9
-
9
+ REGEX_FACEBOOK_PHOTO = /^\/photo\.php$/i
10
+ REGEX_FACEBOOK_ALBUM = /^\/album\.php$/i
11
+
10
12
  def self.included(base)
11
13
  base.class_eval do
12
14
  self::PARSERS[Muri::Filter::Facebook] = "facebook_parse"
13
15
  end
14
16
  end
15
-
17
+
18
+ def self.parsable?(uri)
19
+ uri.host =~ /^(www\.)?facebook\.com$/i
20
+ end
21
+
16
22
  def facebook_parse
17
- @info[:service] = 'Facebook'
18
- params = @url.query.nil? ? {} : CGI::parse(@url.query)#.each {|k,v| b[k] = v.first}
23
+ self.media_service = FACEBOOK_SERVICE_NAME #'Facebook'
24
+ params = Muri.param_parse(self.uri.query)
25
+
19
26
  url_common = "http://www.facebook.com"
20
-
21
- # if @url.path =~ /^\/v\/([0-9]+)/
27
+
28
+ # if self.uri.path =~ /^\/v\/([0-9]+)/
22
29
  # @info[:media_id] = $1
23
30
  # @info[:media_url] = "#{url_common}/v/#{@info[:media_id]}"
24
- #
31
+ #
25
32
  # # Currently no API for video, but media_id is best guess value for such content
26
33
  # @info[:media_api_id] = @info[:media_id]
27
34
  # @info[:media_api_type] = FACEBOOK_VIDEO
28
- if ((@url.path =~ /^\/photo\.php$/i) &&
29
- params.include?("pid") && params["pid"].first =~ /^([0-9]+)$/ &&
30
- params.include?("id") && params["id"].first =~ /^([0-9]+)$/ &&
31
- params.include?("l") && params["l"].first =~ /^([0-9a-z]+)$/i)
32
-
33
- @info[:media_api_type] = FACEBOOK_PHOTO
34
- @info[:media_id] = params["pid"].first
35
- media_creator = params["id"].first
36
- share_key = params["l"].first
37
-
38
- @info[:website] = "#{url_common}/photo.php?pid=#{@info[:media_id]}&l=#{share_key}&id=#{media_creator}"
39
- elsif ((@url.path =~ /^\/album\.php$/i) &&
40
- params.include?("aid") && params["aid"].first =~ /^([0-9]+)$/ &&
41
- params.include?("id") && params["id"].first =~ /^([0-9]+)$/ &&
42
- params.include?("l") && params["l"].first =~ /^([0-9a-z]+)$/i)
43
-
44
- @info[:media_api_type] = FACEBOOK_ALBUM
45
- @info[:media_id] = params["aid"].first
46
- media_creator = params["id"].first
47
- share_key = params["l"].first
48
-
49
- @info[:website] = "#{url_common}/album.php?aid=#{@info[:media_id]}&l=#{share_key}&id=#{media_creator}"
50
- end
51
-
52
- if self.valid?
53
- # The media_api_id is the PID which can be searched for in the facebook photos/albums table
54
- @info[:media_api_id] = (media_creator.to_i << 32) + @info[:media_id].to_i
35
+ if ((self.uri.path =~ REGEX_FACEBOOK_PHOTO) &&
36
+ params["pid"] =~ /^([0-9]+)$/ &&
37
+ params["id"] =~ /^([0-9]+)$/ &&
38
+ params["l"] =~ /^([0-9a-z]+)$/i)
39
+
40
+ self.media_api_type = FACEBOOK_PHOTO
41
+ self.media_id = params["pid"]
42
+ media_creator = params["id"]
43
+ share_key = params["l"]
44
+
45
+ self.media_website = "#{url_common}/photo.php?pid=#{self.media_id}&l=#{share_key}&id=#{media_creator}"
46
+ elsif ((self.uri.path =~ REGEX_FACEBOOK_ALBUM) &&
47
+ params["aid"] =~ /^([0-9]+)$/ &&
48
+ params["id"] =~ /^([0-9]+)$/ &&
49
+ params["l"] =~ /^([0-9a-z]+)$/i)
50
+
51
+ self.media_api_type = FACEBOOK_ALBUM
52
+ self.media_id = params["aid"]
53
+ media_creator = params["id"]
54
+ share_key = params["l"]
55
+
56
+ self.media_website = "#{url_common}/album.php?aid=#{self.media_id}&l=#{share_key}&id=#{media_creator}"
55
57
  else
56
58
  raise UnsupportedURI
57
59
  end
58
-
59
- self
60
- end
61
-
62
- def self.parsable?(uri)
63
- uri.host =~ /^(www\.)?facebook\.com$/i
60
+
61
+ # The media_api_id is the PID which can be searched for in the facebook photos/albums table
62
+ self.media_api_id = (media_creator.to_i << 32) +self.media_id.to_i
64
63
  end
65
-
66
64
  end
67
65
  end
68
66
  end
@@ -73,4 +71,4 @@ end
73
71
  # id = user id
74
72
  # l = photo share key
75
73
  # http://www.facebook.com/v/614695029223 (full) - deprecated
76
- # http://www.facebook.com/album.php?aid=2149275&id=15201063&l=99900807c3
74
+ # http://www.facebook.com/album.php?aid=2149275&id=15201063&l=99900807c3
@@ -1,56 +1,84 @@
1
1
  class Muri
2
2
  module Filter
3
3
  module Flickr
4
-
4
+
5
+ private
5
6
  FLICKR_PHOTO = "photo"
6
7
  FLICKR_SET = "set"
7
-
8
+
9
+ REGEX_FLICKR_PHOTO_OR_SET = /^\/photos\/([a-z0-9\-\_\@]+?)\/(sets\/)?([0-9]+)/i
10
+ REGEX_FLICKR_STATIC_PHOTO = /^farm([1-3])\.static.flickr.com\/([0-9]+?)\/([0-9]+?)\_([a-z0-9]+?)((?:\_[a-z]){1,2}){0,1}\.([a-z]+)/i
11
+ REGEX_FLICKR_SHORTURL = /^flic\.kr\/p\/([a-z0-9]+)/i
12
+
8
13
  def self.included(base)
9
14
  base.class_eval do
10
15
  self::PARSERS[Muri::Filter::Flickr] = "flickr_parse"
11
16
  end
12
17
  end
13
-
18
+
19
+ def self.parsable?(uri)
20
+ uri.host =~ /^(www\.)?(flic\.kr|(farm[0-9]\.static\.|)(flickr)\.com)/i
21
+ end
22
+
14
23
  def flickr_parse
15
- @info[:service] = 'Flickr'
16
-
17
- if @url.path =~ /^\/photos\/([a-z0-9\-\_\@]+?)\/(sets\/)?([0-9]+)/i
24
+ self.media_service = FLICKR_SERVICE_NAME #'Flickr'
25
+
26
+ if self.uri.path =~ REGEX_FLICKR_PHOTO_OR_SET
18
27
  media_creator = $1
19
- @info[:media_id] = $3
20
- @info[:media_api_type] = $2.nil? ? FLICKR_PHOTO : FLICKR_SET
21
- elsif (@url.host + @url.path) =~ /^farm([1-3])\.static.flickr.com\/([0-9]+?)\/([0-9]+?)\_([a-z0-9]+?)(\_[a-z]){0,1}\.([a-z]+)/i
28
+ self.media_id = $3
29
+ self.media_api_type = $2.nil? ? FLICKR_PHOTO : FLICKR_SET
30
+ elsif (self.uri.host + self.uri.path) =~ REGEX_FLICKR_STATIC_PHOTO
22
31
  farm = $1
23
32
  server_id = $2
24
- @info[:media_id] = $3
25
- @info[:media_api_type] = FLICKR_PHOTO
33
+ self.media_id = $3
34
+ self.media_api_type = FLICKR_PHOTO
26
35
  media_secret = $4
27
- url_prefix = "http://farm#{farm}.static.flickr.com/#{server_id}/#{@info[:media_id]}_#{media_secret}"
28
- @info[:media_url] = "#{url_prefix}.jpg"
29
- @info[:media_thumbnail] = "#{url_prefix}_t.jpg"
30
- elsif (@url.host + @url.path) =~ /^flic\.kr\/p\/([a-z0-9]+)/i
31
- @info[:media_id] = self.class.decode58($1)
32
- @info[:media_api_type] = FLICKR_PHOTO
33
- end
34
-
35
- if self.valid?
36
- @info[:media_api_id] = @info[:media_id]
37
- if @info[:media_api_type] == FLICKR_PHOTO
38
- @info[:website] = "http://flic.kr/p/" + self.class.encode58(@info[:media_id].to_i)
39
- elsif @info[:media_api_type] == FLICKR_SET
40
- @info[:website] = "http://www.flickr.com/photos/#{media_creator}/sets/#{@info[:media_id]}"#/show takes direct
41
- end
36
+ url_prefix = "http://farm#{farm}.static.flickr.com/#{server_id}/#{self.media_id}_#{media_secret}"
37
+ self.media_url = "#{url_prefix}.jpg"
38
+ self.media_thumbnail = "#{url_prefix}_t.jpg"
39
+ elsif (self.uri.host + self.uri.path) =~ REGEX_FLICKR_SHORTURL
40
+ self.media_id = Filter::Flickr.decode58($1)
41
+ self.media_api_type = FLICKR_PHOTO
42
42
  else
43
43
  raise UnsupportedURI
44
44
  end
45
-
46
- self
45
+
46
+ self.media_api_id = self.media_id
47
+ if self.is_flickr_photo?
48
+ self.media_website = "http://flic.kr/p/" + Filter::Flickr.encode58(self.media_id.to_i)
49
+ elsif self.is_flickr_set?
50
+ self.media_website = "http://www.flickr.com/photos/#{media_creator}/sets/#{self.media_id}" # appending /show takes direct to image through redirect
51
+ end
47
52
  end
48
53
 
49
- def self.parsable?(uri)
50
- uri.host =~ /^(www\.)?(flic\.kr|(farm[0-9]\.static\.|)(flickr)\.com)/i
51
- end
52
-
53
-
54
+ # Ported from PHP.
55
+ def self.decode58(str)
56
+ decoded = 0
57
+ multi = 1
58
+ alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
59
+ while str.length > 0
60
+ digit = str[(str.length - 1),1]
61
+ decoded += multi * alphabet.index(digit)
62
+ multi = multi * alphabet.length
63
+ str.chop!
64
+ end
65
+ decoded
66
+ end
67
+
68
+ # Ported from PHP.
69
+ def self.encode58(str)
70
+ alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
71
+ base_count = alphabet.length
72
+ encoded = ''
73
+ while str >= base_count
74
+ div = str / base_count
75
+ mod = (str-(base_count * div))
76
+ encoded = alphabet[mod,1] + encoded
77
+ str = div
78
+ end
79
+ encoded = (alphabet[str,1] + encoded) if str
80
+ encoded
81
+ end
54
82
  end
55
83
  end
56
84
  end
@@ -61,7 +89,7 @@ end
61
89
  # when '_m' then 'small'
62
90
  # when '_b' then 'large'
63
91
  # when '_o' then 'original'
64
- # else nil
92
+ # else 'medium'
65
93
  # end
66
94
  # end
67
95
  # @info[:content_type] = $6
@@ -2,43 +2,40 @@ class Muri
2
2
  module Filter
3
3
  module Imageshack
4
4
 
5
+ private
6
+
5
7
  def self.included(base)
6
8
  base.class_eval do
7
9
  self::PARSERS[Muri::Filter::Imageshack] = "imageshack_parse"
8
10
  end
9
11
  end
10
-
12
+
13
+ def self.parsable?(uri)
14
+ uri.host =~ /^img([0-9]*?)\.imageshack\.us$/i #/^(img([0-9]*?)\.imageshack\.us)|(yfrog\.com)/i
15
+ end
16
+
11
17
  def imageshack_parse
12
- @info[:service] = 'Imageshack'
13
-
14
- @url.host =~ /^img([0-9]*?)\.imageshack\.us/i
18
+ self.media_service = IMAGESHACK_SERVICE_NAME #'Imageshack'
19
+
20
+ self.uri.host =~ /^img([0-9]*?)\.imageshack\.us/i
15
21
  server_id = $1
16
22
  url_common = "http://img#{server_id}.imageshack.us"
17
-
18
- if @url.path =~ /^\/i\/([a-z0-9]+?)\.([a-z0-9]+)(\/)?/i
19
- @info[:media_id] = $1
20
- @info[:content_type] = $2
21
- elsif @url.path =~ /^\/img([0-9]*?)\/([0-9]+?)\/([a-z0-9]+?)\.([a-z0-9]+)/i
23
+
24
+ if self.uri.path =~ /^\/i\/([a-z0-9]+?)\.([a-z0-9]+)(\/)?/i
25
+ self.media_id = $1
26
+ self.media_content_type = $2
27
+ elsif self.uri.path =~ /^\/img([0-9]*?)\/([0-9]+?)\/([a-z0-9]+?)\.([a-z0-9]+)/i
22
28
  content_server_id = $2
23
- @info[:media_id] = $3
24
- @info[:content_type] = $4
25
- @info[:media_url] = "#{url_common}/img#{server_id}/#{content_server_id}/#{@info[:media_id]}.#{@info[:content_type]}"
26
- end
27
-
28
- # imageshack does not currently have API for retrieving individual video information
29
- if self.valid?
30
- @info[:website] = "#{url_common}/i/#{@info[:media_id]}.#{@info[:content_type]}/"
29
+ self.media_id = $3
30
+ self.media_content_type = $4
31
+ self.media_url = "#{url_common}/img#{server_id}/#{content_server_id}/#{self.media_id}.#{self.media_content_type}"
31
32
  else
32
- raise UnsupportedURI
33
+ raise UnsupportedURI
33
34
  end
34
-
35
- self
36
- end
37
-
38
- def self.parsable?(uri)
39
- uri.host =~ /^img([0-9]*?)\.imageshack\.us$/i #/^(img([0-9]*?)\.imageshack\.us)|(yfrog\.com)/i
40
- end
41
-
35
+
36
+ # imageshack does not currently have API for retrieving individual video information
37
+ self.media_website = "#{url_common}/i/#{self.media_id}.#{self.media_content_type}/"
38
+ end
42
39
  end
43
40
  end
44
41
  end