acts_as_unvlogable_2 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.travis.yml +16 -0
- data/Gemfile +14 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +130 -0
- data/Rakefile +2 -0
- data/acts_as_unvlogable.gemspec +25 -0
- data/lib/acts_as_unvlogable.rb +117 -0
- data/lib/acts_as_unvlogable/flickr.rb +713 -0
- data/lib/acts_as_unvlogable/object_base.rb +15 -0
- data/lib/acts_as_unvlogable/string_base.rb +24 -0
- data/lib/acts_as_unvlogable/string_extend.rb +8 -0
- data/lib/acts_as_unvlogable/version.rb +3 -0
- data/lib/acts_as_unvlogable/vg_11870.rb +48 -0
- data/lib/acts_as_unvlogable/vg_blip.rb +48 -0
- data/lib/acts_as_unvlogable/vg_collegehumor.rb +58 -0
- data/lib/acts_as_unvlogable/vg_dailymotion.rb +67 -0
- data/lib/acts_as_unvlogable/vg_dalealplay.rb +50 -0
- data/lib/acts_as_unvlogable/vg_flickr.rb +70 -0
- data/lib/acts_as_unvlogable/vg_marca.rb +48 -0
- data/lib/acts_as_unvlogable/vg_metacafe.rb +77 -0
- data/lib/acts_as_unvlogable/vg_myspace.rb +48 -0
- data/lib/acts_as_unvlogable/vg_prostopleer.rb +46 -0
- data/lib/acts_as_unvlogable/vg_qik.rb +64 -0
- data/lib/acts_as_unvlogable/vg_rutube.rb +80 -0
- data/lib/acts_as_unvlogable/vg_ted.rb +51 -0
- data/lib/acts_as_unvlogable/vg_vimeo.rb +89 -0
- data/lib/acts_as_unvlogable/vg_youtu.rb +11 -0
- data/lib/acts_as_unvlogable/vg_youtube.rb +67 -0
- data/test/acts_as_unvlogable_test.rb +392 -0
- data/test/video_factory_test.rb +66 -0
- data/unvlogable_sample.yml +5 -0
- metadata +137 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f4f66fb07e85f15f6e72be62dd7e13b862f8d039
|
4
|
+
data.tar.gz: 4dc34b2c0108033653d18591fc079aaf5d78f820
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3dd6c6e49b051cd4f510d9eec2ee18999561215c8e4cb0aa1790437f1440cf455e44ccf03461ddd5e748123711790d585e95b61c95ceb4e86fc8c5699d793a47
|
7
|
+
data.tar.gz: ff137715a74e0eacc3f22fd445e490fbbc5d59ed9a698232a6b952b9dfd6176f6e5ea50a662140f65277157fa6941a78984d7078ca89f5ea5c5cd547eea6c94b
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 unvlog.com
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
Acts as unvlogable
|
2
|
+
==================
|
3
|
+
|
4
|
+
What the hell is this!
|
5
|
+
----------------------
|
6
|
+
|
7
|
+
This is the plugin that we use in [unvlog.com](http://unvlog.com) to manage the supported video services. It is an easy way to obtain a few basics about a video only through its url.
|
8
|
+
|
9
|
+
A quick example:
|
10
|
+
|
11
|
+
To include [this video](http://www.youtube.com/watch?v=GPQnbtldFyo) in [this post](http://unvlog.com/blat/2008/3/10/otro-pelotazo) we need to know its title, the correct way to embed it and its thumbnail url. With this plugin we have an easy access to this data:
|
12
|
+
|
13
|
+
@aha = UnvlogIt.new("http://www.youtube.com/watch?v=GPQnbtldFyo")
|
14
|
+
@aha.title => "paradon del portero"
|
15
|
+
@aha.thumbnail => "http://i4.ytimg.com/vi/GPQnbtldFyo/default.jpg"
|
16
|
+
@aha.embed_url => "http://www.youtube.com/v/GPQnbtldFyo"
|
17
|
+
@aha.embed_html(width, height) => "<object [...]</object>"
|
18
|
+
@aha.flv => "http://...flv"
|
19
|
+
# all together :)
|
20
|
+
@aha.video_details(width, height) => {
|
21
|
+
:title => ...,
|
22
|
+
:thumbnail => ...,
|
23
|
+
:embed_url => ...,
|
24
|
+
:embed_html => ...,
|
25
|
+
:flv => ...
|
26
|
+
}
|
27
|
+
|
28
|
+
With this plugin we have an unique way to manage multiple services :)
|
29
|
+
|
30
|
+
|
31
|
+
Install it!
|
32
|
+
-----------
|
33
|
+
|
34
|
+
1. Install it as a gem:
|
35
|
+
|
36
|
+
gem "acts_as_unvlogable"
|
37
|
+
|
38
|
+
2. Optionally you can create the `config/unvlogable.yml` to store keys for the different services. You have in the plugin a [sample file](http://github.com/mamuso/acts_as_unvlogable/tree/master/unvlogable_sample.yml). At this moment you only need specify keys for flickr.
|
39
|
+
|
40
|
+
|
41
|
+
Dependencies
|
42
|
+
------------
|
43
|
+
|
44
|
+
The plugin depends on [youtube-it](https://github.com/kylejginavan/youtube_it), [xml-simple](http://xml-simple.rubyforge.org/) and [hpricot](https://code.whytheluckystiff.net/hpricot/).
|
45
|
+
|
46
|
+
We have included a modified version of the flickr gem to skip the gem dependency and manage video capabilities.
|
47
|
+
|
48
|
+
|
49
|
+
Use it!
|
50
|
+
-------
|
51
|
+
|
52
|
+
|
53
|
+
The idea is make it as simple as possible. For a given video URL as <http://vimeo.com/1785993>:
|
54
|
+
|
55
|
+
videotron = UnvlogIt.new("http://vimeo.com/1785993")
|
56
|
+
|
57
|
+
Then we have methods to know the 'basics' for use this video on your application.
|
58
|
+
|
59
|
+
- __title:__ A method to know the title of the video on the service.
|
60
|
+
|
61
|
+
videotron.title
|
62
|
+
=> "Beached"
|
63
|
+
|
64
|
+
- __service:__ A method to know the name of the video provider service.
|
65
|
+
|
66
|
+
videotron.service
|
67
|
+
=> "Vimeo"
|
68
|
+
|
69
|
+
- __thumbnail:__ An image representation of the video. Each service has a different size, but... it works :)
|
70
|
+
|
71
|
+
videotron.thumbnail
|
72
|
+
=> "http://bc1.vimeo.com/vimeo/thumbs/143104745_640.jpg"
|
73
|
+
|
74
|
+
- __embed\_url:__ The url (with flashvars) of the video player.
|
75
|
+
|
76
|
+
videotron.embed_url
|
77
|
+
=> "http://vimeo.com/moogaloop.swf?clip_id=1785993 [...] &show_portrait=1"
|
78
|
+
|
79
|
+
- __embed\_html(width, height):__ Uses the embed\_url to build an oembed string. The default width x height is 425 x 344, but we can specify a different one.
|
80
|
+
|
81
|
+
videotron.embed_html(400, 300)
|
82
|
+
=> "<object width='400' height='300'><param name='mo [...] 300'></embed></object>"
|
83
|
+
|
84
|
+
- __flv:__ Gets the flv url. In this edition we implement this method in all the services, but is possible that we can't get the flv in some scenarios. Remember that in some services the flv url expires and in most of their terms don't allow use the flv without its player.
|
85
|
+
|
86
|
+
videotron.flv
|
87
|
+
=> "http://www.vimeo.com/moogaloop/play/clip:1785993/ [...] 8ee400/video.flv"
|
88
|
+
|
89
|
+
- __video\_details(width, height):__ All together :), returns all the previous elements in a hash. Width and height can be specified to build the embed\_html.
|
90
|
+
|
91
|
+
videotron.video_details
|
92
|
+
=> "{ [...] }"
|
93
|
+
|
94
|
+
|
95
|
+
Supported services
|
96
|
+
------------------
|
97
|
+
|
98
|
+
At this moment we support the following video services:
|
99
|
+
|
100
|
+
- [Youtube](http://www.youtube.com/)
|
101
|
+
- [Vimeo](http://vimeo.com/)
|
102
|
+
- [Flickr (videos)](http://flickr.com/)
|
103
|
+
- [Metacafe](http://metacafe.com/)
|
104
|
+
- [Dailymotion](http://dailymotion.com/)
|
105
|
+
- [Collegehumor](http://collegehumor.com/)
|
106
|
+
- [Blip.tv](http://blip.tv/)
|
107
|
+
- [Myspace](http://vids.myspace.com/)
|
108
|
+
- [Ted Talks](http://www.ted.com/talks/)
|
109
|
+
- [11870.com](http://11870.com/)
|
110
|
+
- [Marca.tv](http://www.marca.tv/)
|
111
|
+
- [Dalealplay](http://www.dalealplay.com/)
|
112
|
+
- [RuTube](http://www.rutube.ru/)
|
113
|
+
|
114
|
+
Broken services
|
115
|
+
---------------
|
116
|
+
|
117
|
+
These services were implemented but due to changes in the website they don't work anymore. Any patch for fixing them would be great ;)
|
118
|
+
|
119
|
+
- [Qik](http://qik.com/)
|
120
|
+
- [MTV](http://www.mtvhive.com/)
|
121
|
+
|
122
|
+
You can detect new broken services when running the tests.
|
123
|
+
|
124
|
+
We are always open to incude new services.
|
125
|
+
|
126
|
+
And... what else?
|
127
|
+
-----------------
|
128
|
+
If you find a bug or want to suggest a new video service, please tell it to us in [a ticket](http://github.com/mamuso/acts_as_unvlogable/issues).
|
129
|
+
|
130
|
+
Thanks!!
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "acts_as_unvlogable/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "acts_as_unvlogable_2"
|
7
|
+
s.version = ActsAsUnvlogable::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Manuel Muñoz", "Fernando Blat", "Alberto Romero"]
|
10
|
+
s.email = ["mamusino@gmail.com", "ferblape@gmail.com", "denegro@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/mamuso/acts_as_unvlogable"
|
12
|
+
s.summary = %q{An easy way to include external video services in a rails app}
|
13
|
+
s.description = %q{An easy way to include external video services in a rails app. This gem provides you wrappers for the most common video services, such as Youtube, Vimeo, Flickr, and so on...}
|
14
|
+
|
15
|
+
s.rubyforge_project = "acts_as_unvlogable"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.add_development_dependency "shoulda"
|
22
|
+
s.add_dependency("xml-simple")
|
23
|
+
s.add_dependency("youtube_it")
|
24
|
+
s.add_dependency("hpricot")
|
25
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
|
+
|
4
|
+
require "xmlsimple"
|
5
|
+
require "youtube_it"
|
6
|
+
require "hpricot"
|
7
|
+
require "net/http"
|
8
|
+
require "json"
|
9
|
+
|
10
|
+
require "acts_as_unvlogable/flickr"
|
11
|
+
# Extensions
|
12
|
+
if defined?(ActiveSupport).nil?
|
13
|
+
require "acts_as_unvlogable/string_base"
|
14
|
+
require "acts_as_unvlogable/object_base"
|
15
|
+
end
|
16
|
+
require "acts_as_unvlogable/string_extend"
|
17
|
+
|
18
|
+
# Video classes
|
19
|
+
videolibs = File.join(File.dirname(__FILE__), "acts_as_unvlogable", "vg_*.rb")
|
20
|
+
Dir.glob(videolibs).each {|file| require file}
|
21
|
+
|
22
|
+
class UnvlogIt
|
23
|
+
|
24
|
+
def initialize(url=nil, options={})
|
25
|
+
@object = VideoFactory.new(url, options).load_service
|
26
|
+
end
|
27
|
+
|
28
|
+
def title
|
29
|
+
@object.title #rescue nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def thumbnail
|
33
|
+
@object.thumbnail rescue nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def duration # duration is in seconds
|
37
|
+
@object.duration rescue nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def embed_url
|
41
|
+
@object.embed_url rescue nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def video_id
|
45
|
+
@object.video_id rescue nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def embed_html(width=425, height=344, options={}, params={})
|
49
|
+
@object.embed_html(width, height, options, params) rescue nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def flv
|
53
|
+
@object.flv #rescue nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def download_url
|
57
|
+
@object.download_url rescue nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def service
|
61
|
+
@object.service rescue nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def video_details(width=425, height=344)
|
65
|
+
{
|
66
|
+
:title => @object.title,
|
67
|
+
:thumbnail => @object.thumbnail,
|
68
|
+
:embed_url => @object.embed_url,
|
69
|
+
:embed_html => @object.embed_html(width, height),
|
70
|
+
:flv => @object.flv,
|
71
|
+
:download_url => @object.download_url,
|
72
|
+
:service => @object.service,
|
73
|
+
:duration => @object.duration
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
class VideoFactory
|
78
|
+
def initialize(url, options = {})
|
79
|
+
raise ArgumentError.new("We need a video url") if url.blank?
|
80
|
+
@url = url
|
81
|
+
@options = options
|
82
|
+
end
|
83
|
+
|
84
|
+
def load_service
|
85
|
+
@object = service_object
|
86
|
+
|
87
|
+
validate_embed(@object)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def validate_embed(object)
|
93
|
+
unless object.instance_variable_get("@details").nil? || !object.instance_variable_get("@details").respond_to?("noembed")
|
94
|
+
if object.instance_variable_get("@details").noembed
|
95
|
+
raise ArgumentError.new("Embedding disabled by request")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
object
|
99
|
+
end
|
100
|
+
|
101
|
+
def service_object
|
102
|
+
class_name = "vg_#{get_domain.downcase}".camelize
|
103
|
+
class_name.constantize.new(@url, @options)
|
104
|
+
rescue NameError
|
105
|
+
raise ArgumentError.new("Unsuported url or service. class: #{class_name}, url: #{@url}")
|
106
|
+
end
|
107
|
+
|
108
|
+
def get_domain
|
109
|
+
host = URI::parse(@url).host.split(".")
|
110
|
+
unless host.size == 1
|
111
|
+
host[host.size-2]
|
112
|
+
else
|
113
|
+
host[0]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,713 @@
|
|
1
|
+
# included here to skip the gem dependency and modified to manage video capabilities.
|
2
|
+
# this is the updated version from http://github.com/ctagg/flickr/tree/master/lib/flickr.rb
|
3
|
+
|
4
|
+
# = Flickr
|
5
|
+
# An insanely easy interface to the Flickr photo-sharing service. By Scott Raymond.
|
6
|
+
#
|
7
|
+
# Author:: Scott Raymond <sco@redgreenblu.com>
|
8
|
+
# Copyright:: Copyright (c) 2005 Scott Raymond <sco@redgreenblu.com>. Additional content by Patrick Plattes and Chris Taggart (http://pushrod.wordpress.com)
|
9
|
+
# License:: MIT <http://www.opensource.org/licenses/mit-license.php>
|
10
|
+
#
|
11
|
+
# BASIC USAGE:
|
12
|
+
# require 'flickr'
|
13
|
+
# flickr = Flickr.new('some_flickr_api_key') # create a flickr client (get an API key from http://www.flickr.com/services/api/)
|
14
|
+
# user = flickr.users('sco@scottraymond.net') # lookup a user
|
15
|
+
# user.name # get the user's name
|
16
|
+
# user.location # and location
|
17
|
+
# user.photos # grab their collection of Photo objects...
|
18
|
+
# user.groups # ...the groups they're in...
|
19
|
+
# user.contacts # ...their contacts...
|
20
|
+
# user.favorites # ...favorite photos...
|
21
|
+
# user.photosets # ...their photo sets...
|
22
|
+
# user.tags # ...and their tags
|
23
|
+
# recentphotos = flickr.photos # get the 100 most recent public photos
|
24
|
+
# photo = recentphotos.first # or very most recent one
|
25
|
+
# photo.url # see its URL,
|
26
|
+
# photo.title # title,
|
27
|
+
# photo.description # and description,
|
28
|
+
# photo.owner # and its owner.
|
29
|
+
# File.open(photo.filename, 'w') do |file|
|
30
|
+
# file.puts p.file # save the photo to a local file
|
31
|
+
# end
|
32
|
+
# flickr.photos.each do |p| # get the last 100 public photos...
|
33
|
+
# File.open(p.filename, 'w') do |f|
|
34
|
+
# f.puts p.file('Square') # ...and save a local copy of their square thumbnail
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
|
38
|
+
|
39
|
+
require 'cgi'
|
40
|
+
require 'net/http'
|
41
|
+
require 'xmlsimple'
|
42
|
+
require 'digest/md5'
|
43
|
+
|
44
|
+
# Flickr client class. Requires an API key
|
45
|
+
class Flickr
|
46
|
+
attr_reader :api_key, :auth_token
|
47
|
+
attr_accessor :user
|
48
|
+
|
49
|
+
HOST_URL = 'http://flickr.com'
|
50
|
+
API_PATH = '/services/rest'
|
51
|
+
|
52
|
+
# Flickr, annoyingly, uses a number of representations to specify the size
|
53
|
+
# of a photo, depending on the context. It gives a label such a "Small" or
|
54
|
+
# "Medium" to a size of photo, when returning all possible sizes. However,
|
55
|
+
# when generating the uri for the page that features that size of photo, or
|
56
|
+
# the source url for the image itself it uses a single letter. Bizarrely,
|
57
|
+
# these letters are different depending on whether you want the Flickr page
|
58
|
+
# for the photo or the source uri -- e.g. a "Small" photo (240 pixels on its
|
59
|
+
# longest side) may be viewed at
|
60
|
+
# "http://www.flickr.com/photos/sco/2397458775/sizes/s/"
|
61
|
+
# but its source is at
|
62
|
+
# "http://farm4.static.flickr.com/3118/2397458775_2ec2ddc324_m.jpg".
|
63
|
+
# The VALID_SIZES hash associates the correct letter with a label
|
64
|
+
VALID_SIZES = { "Square" => ["s", "sq"],
|
65
|
+
"Thumbnail" => ["t", "t"],
|
66
|
+
"Small" => ["m", "s"],
|
67
|
+
"Medium" => [nil, "m"],
|
68
|
+
"Large" => ["b", "l"]
|
69
|
+
}
|
70
|
+
|
71
|
+
# To use the Flickr API you need an api key
|
72
|
+
# (see http://www.flickr.com/services/api/misc.api_keys.html), and the flickr
|
73
|
+
# client object shuld be initialized with this. You'll also need a shared
|
74
|
+
# secret code if you want to use authentication (e.g. to get a user's
|
75
|
+
# private photos)
|
76
|
+
# There are two ways to initialize the Flickr client. The preferred way is with
|
77
|
+
# a hash of params, e.g. 'api_key' => 'your_api_key', 'shared_secret' =>
|
78
|
+
# 'shared_secret_code'. The older (deprecated) way is to pass an ordered series of
|
79
|
+
# arguments. This is provided for continuity only, as several of the arguments
|
80
|
+
# are no longer usable ('email', 'password')
|
81
|
+
def initialize(api_key_or_params=nil, email=nil, password=nil, shared_secret=nil)
|
82
|
+
@host = HOST_URL
|
83
|
+
@api = API_PATH
|
84
|
+
if api_key_or_params.is_a?(Hash)
|
85
|
+
@api_key = api_key_or_params['api_key']
|
86
|
+
@shared_secret = api_key_or_params['shared_secret']
|
87
|
+
@auth_token = api_key_or_params['auth_token']
|
88
|
+
else
|
89
|
+
@api_key = api_key_or_params
|
90
|
+
@shared_secret = shared_secret
|
91
|
+
login(email, password) if email and password
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Gets authentication token given a Flickr frob, which is returned when user
|
96
|
+
# allows access to their account for the application with the api_key which
|
97
|
+
# made the request
|
98
|
+
def get_token_from(frob)
|
99
|
+
auth_response = request("auth.getToken", :frob => frob)['auth']
|
100
|
+
@auth_token = auth_response['token']
|
101
|
+
@user = User.new( 'id' => auth_response['user']['nsid'],
|
102
|
+
'username' => auth_response['user']['username'],
|
103
|
+
'name' => auth_response['user']['fullname'],
|
104
|
+
'client' => self)
|
105
|
+
@auth_token
|
106
|
+
end
|
107
|
+
|
108
|
+
# Stores authentication credentials to use on all subsequent calls.
|
109
|
+
# If authentication succeeds, returns a User object.
|
110
|
+
# NB This call is no longer in API and will result in an error if called
|
111
|
+
def login(email='', password='')
|
112
|
+
@email = email
|
113
|
+
@password = password
|
114
|
+
user = request('test.login')['user'] rescue fail
|
115
|
+
@user = User.new(user['id'], nil, nil, nil, @api_key)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Implements flickr.urls.lookupGroup and flickr.urls.lookupUser
|
119
|
+
def find_by_url(url)
|
120
|
+
response = urls_lookupUser('url'=>url) rescue urls_lookupGroup('url'=>url) rescue nil
|
121
|
+
(response['user']) ? User.new(response['user']['id'], nil, nil, nil, @api_key) : Group.new(response['group']['id'], @api_key) unless response.nil?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Implements flickr.photos.getRecent and flickr.photos.search
|
125
|
+
def photos(*criteria)
|
126
|
+
criteria ? photos_search(*criteria) : recent
|
127
|
+
end
|
128
|
+
|
129
|
+
# flickr.photos.getRecent
|
130
|
+
# 100 newest photos from everyone
|
131
|
+
def recent
|
132
|
+
photos_request('photos.getRecent')
|
133
|
+
end
|
134
|
+
|
135
|
+
def photos_search(params={})
|
136
|
+
photos_request('photos.search', params)
|
137
|
+
end
|
138
|
+
alias_method :search, :photos_search
|
139
|
+
|
140
|
+
# Gets public photos with a given tag
|
141
|
+
def tag(tag)
|
142
|
+
photos('tags'=>tag)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Implements flickr.people.findByEmail and flickr.people.findByUsername.
|
146
|
+
def users(lookup=nil)
|
147
|
+
user = people_findByEmail('find_email'=>lookup)['user'] rescue people_findByUsername('username'=>lookup)['user']
|
148
|
+
return User.new("id" => user["nsid"], "username" => user["username"], "client" => self)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Implements flickr.groups.search
|
152
|
+
def groups(group_name, options={})
|
153
|
+
collection = groups_search({"text" => group_name}.merge(options))['groups']['group']
|
154
|
+
collection = [collection] if collection.is_a? Hash
|
155
|
+
|
156
|
+
collection.collect { |group| Group.new( "id" => group['nsid'],
|
157
|
+
"name" => group['name'],
|
158
|
+
"eighteenplus" => group['eighteenplus'],
|
159
|
+
"client" => self) }
|
160
|
+
end
|
161
|
+
|
162
|
+
# Implements flickr.tags.getRelated
|
163
|
+
def related_tags(tag)
|
164
|
+
tags_getRelated('tag'=>tag)['tags']['tag']
|
165
|
+
end
|
166
|
+
|
167
|
+
# Implements flickr.photos.licenses.getInfo
|
168
|
+
def licenses
|
169
|
+
photos_licenses_getInfo['licenses']['license']
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns url for user to login in to Flickr to authenticate app for a user
|
173
|
+
def login_url(perms)
|
174
|
+
"http://flickr.com/services/auth/?api_key=#{@api_key}&perms=#{perms}&api_sig=#{signature_from('api_key'=>@api_key, 'perms' => perms)}"
|
175
|
+
end
|
176
|
+
|
177
|
+
# Implements everything else.
|
178
|
+
# Any method not defined explicitly will be passed on to the Flickr API,
|
179
|
+
# and return an XmlSimple document. For example, Flickr#test_echo is not
|
180
|
+
# defined, so it will pass the call to the flickr.test.echo method.
|
181
|
+
def method_missing(method_id, params={})
|
182
|
+
request(method_id.id2name.gsub(/_/, '.'), params)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Does an HTTP GET on a given URL and returns the response body
|
186
|
+
def http_get(url)
|
187
|
+
Net::HTTP.get_response(URI.parse(url)).body.to_s
|
188
|
+
end
|
189
|
+
|
190
|
+
# Takes a Flickr API method name and set of parameters; returns an XmlSimple object with the response
|
191
|
+
def request(method, params={})
|
192
|
+
url = request_url(method, params)
|
193
|
+
response = XmlSimple.xml_in(open(url), { 'ForceArray' => false })
|
194
|
+
raise response['err']['msg'] if response['stat'] != 'ok'
|
195
|
+
response
|
196
|
+
end
|
197
|
+
|
198
|
+
# acts like request but returns a PhotoCollection (a list of Photo objects)
|
199
|
+
def photos_request(method, params={})
|
200
|
+
photos = request(method, params)
|
201
|
+
PhotoCollection.new(photos, @api_key)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Builds url for Flickr API REST request from given the flickr method name
|
205
|
+
# (exclusing the 'flickr.' that begins each method call) and params (where
|
206
|
+
# applicable) which should be supplied as a Hash (e.g 'user_id' => "foo123")
|
207
|
+
def request_url(method, params={})
|
208
|
+
method = 'flickr.' + method
|
209
|
+
url = "#{@host}#{@api}/?api_key=#{@api_key}&method=#{method}"
|
210
|
+
params.merge!('api_key' => @api_key, 'method' => method, 'auth_token' => @auth_token)
|
211
|
+
signature = signature_from(params)
|
212
|
+
|
213
|
+
url = "#{@host}#{@api}/?" + params.merge('api_sig' => signature).collect { |k,v| "#{k}=" + CGI::escape(v.to_s) unless v.nil? }.compact.join("&")
|
214
|
+
end
|
215
|
+
|
216
|
+
def signature_from(params={})
|
217
|
+
return unless @shared_secret # don't both getting signature if no shared_secret
|
218
|
+
request_str = params.reject {|k,v| v.nil?}.collect {|p| "#{p[0].to_s}#{p[1]}"}.sort.join # build key value pairs, sort in alpha order then join them, ignoring those with nil value
|
219
|
+
return Digest::MD5.hexdigest("#{@shared_secret}#{request_str}")
|
220
|
+
end
|
221
|
+
|
222
|
+
# A collection of photos is returned as a PhotoCollection, a subclass of Array.
|
223
|
+
# This allows us to retain the pagination info returned by Flickr and make it
|
224
|
+
# accessible in a friendly way
|
225
|
+
class PhotoCollection < Array
|
226
|
+
attr_reader :page, :pages, :perpage, :total
|
227
|
+
|
228
|
+
# builds a PhotoCollection from given params, such as those returned from
|
229
|
+
# photos.search API call
|
230
|
+
def initialize(photos_api_response={}, api_key=nil)
|
231
|
+
[ "page", "pages", "perpage", "total" ].each { |i| instance_variable_set("@#{i}", photos_api_response["photos"][i])}
|
232
|
+
collection = photos_api_response['photos']['photo'] || []
|
233
|
+
collection = [collection] if collection.is_a? Hash
|
234
|
+
collection.each { |photo| self << Photo.new(photo.delete('id'), api_key, photo) }
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Todo:
|
239
|
+
# logged_in?
|
240
|
+
# if logged in:
|
241
|
+
# flickr.blogs.getList
|
242
|
+
# flickr.favorites.add
|
243
|
+
# flickr.favorites.remove
|
244
|
+
# flickr.groups.browse
|
245
|
+
# flickr.photos.getCounts
|
246
|
+
# flickr.photos.getNotInSet
|
247
|
+
# flickr.photos.getUntagged
|
248
|
+
# flickr.photosets.create
|
249
|
+
# flickr.photosets.orderSets
|
250
|
+
# flickr.tags.getListUserPopular
|
251
|
+
# flickr.test.login
|
252
|
+
# uploading
|
253
|
+
class User
|
254
|
+
|
255
|
+
attr_reader :client, :id, :name, :location, :photos_url, :url, :count, :firstdate, :firstdatetaken
|
256
|
+
|
257
|
+
# A Flickr::User can be instantiated in two ways. The old (deprecated)
|
258
|
+
# method is with an ordered series of values. The new method is with a
|
259
|
+
# params Hash, which is easier when a variable number of params are
|
260
|
+
# supplied, which is the case here, and also avoids having to constantly
|
261
|
+
# supply nil values for the email and password, which are now irrelevant
|
262
|
+
# as authentication is no longer done this way.
|
263
|
+
# An associated flickr client will also be generated if an api key is
|
264
|
+
# passed among the arguments or in the params hash. Alternatively, and
|
265
|
+
# most likely, an existing client object may be passed in the params hash
|
266
|
+
# (e.g. 'client' => some_existing_flickr_client_object), and this is
|
267
|
+
# what happends when users are initlialized as the result of a method
|
268
|
+
# called on the flickr client (e.g. flickr.users)
|
269
|
+
def initialize(id_or_params_hash=nil, username=nil, email=nil, password=nil, api_key=nil)
|
270
|
+
if id_or_params_hash.is_a?(Hash)
|
271
|
+
id_or_params_hash.each { |k,v| self.instance_variable_set("@#{k}", v) } # convert extra_params into instance variables
|
272
|
+
else
|
273
|
+
@id = id_or_params_hash
|
274
|
+
@username = username
|
275
|
+
@email = email
|
276
|
+
@password = password
|
277
|
+
@api_key = api_key
|
278
|
+
end
|
279
|
+
@client ||= Flickr.new('api_key' => @api_key, 'shared_secret' => @shared_secret, 'auth_token' => @auth_token) if @api_key
|
280
|
+
@client.login(@email, @password) if @email and @password # this is now irrelevant as Flickr API no longer supports authentication this way
|
281
|
+
end
|
282
|
+
|
283
|
+
def username
|
284
|
+
@username.nil? ? getInfo.username : @username
|
285
|
+
end
|
286
|
+
def name
|
287
|
+
@name.nil? ? getInfo.name : @name
|
288
|
+
end
|
289
|
+
def location
|
290
|
+
@location.nil? ? getInfo.location : @location
|
291
|
+
end
|
292
|
+
def count
|
293
|
+
@count.nil? ? getInfo.count : @count
|
294
|
+
end
|
295
|
+
def firstdate
|
296
|
+
@firstdate.nil? ? getInfo.firstdate : @firstdate
|
297
|
+
end
|
298
|
+
def firstdatetaken
|
299
|
+
@firstdatetaken.nil? ? getInfo.firstdatetaken : @firstdatetaken
|
300
|
+
end
|
301
|
+
|
302
|
+
# Builds url for user's photos page as per
|
303
|
+
# http://www.flickr.com/services/api/misc.urls.html
|
304
|
+
def photos_url
|
305
|
+
"http://www.flickr.com/photos/#{id}/"
|
306
|
+
end
|
307
|
+
|
308
|
+
# Builds url for user's profile page as per
|
309
|
+
# http://www.flickr.com/services/api/misc.urls.html
|
310
|
+
def url
|
311
|
+
"http://www.flickr.com/people/#{id}/"
|
312
|
+
end
|
313
|
+
|
314
|
+
def pretty_url
|
315
|
+
@pretty_url ||= @client.urls_getUserProfile('user_id'=>@id)['user']['url']
|
316
|
+
end
|
317
|
+
|
318
|
+
# Implements flickr.people.getPublicGroups
|
319
|
+
def groups
|
320
|
+
collection = @client.people_getPublicGroups('user_id'=>@id)['groups']['group']
|
321
|
+
collection = [collection] if collection.is_a? Hash
|
322
|
+
collection.collect { |group| Group.new( "id" => group['nsid'],
|
323
|
+
"name" => group['name'],
|
324
|
+
"eighteenplus" => group['eighteenplus'],
|
325
|
+
"client" => @client) }
|
326
|
+
end
|
327
|
+
|
328
|
+
# Implements flickr.people.getPublicPhotos. Options hash allows you to add
|
329
|
+
# extra restrictions as per flickr.people.getPublicPhotos docs, e.g.
|
330
|
+
# user.photos('per_page' => '25', 'extras' => 'date_taken')
|
331
|
+
def photos(options={})
|
332
|
+
@client.photos_request('people.getPublicPhotos', {'user_id' => @id}.merge(options))
|
333
|
+
# what about non-public photos?
|
334
|
+
end
|
335
|
+
|
336
|
+
# Gets photos with a given tag
|
337
|
+
def tag(tag)
|
338
|
+
@client.photos('user_id'=>@id, 'tags'=>tag)
|
339
|
+
end
|
340
|
+
|
341
|
+
# Implements flickr.contacts.getPublicList and flickr.contacts.getList
|
342
|
+
def contacts
|
343
|
+
@client.contacts_getPublicList('user_id'=>@id)['contacts']['contact'].collect { |contact| User.new(contact['nsid'], contact['username'], nil, nil, @api_key) }
|
344
|
+
#or
|
345
|
+
end
|
346
|
+
|
347
|
+
# Implements flickr.favorites.getPublicList
|
348
|
+
def favorites
|
349
|
+
@client.photos_request('favorites.getPublicList', 'user_id' => @id)
|
350
|
+
end
|
351
|
+
|
352
|
+
# Implements flickr.photosets.getList
|
353
|
+
def photosets
|
354
|
+
@client.photosets_getList('user_id'=>@id)['photosets']['photoset'].collect { |photoset| Photoset.new(photoset['id'], @api_key) }
|
355
|
+
end
|
356
|
+
|
357
|
+
# Implements flickr.tags.getListUser
|
358
|
+
def tags
|
359
|
+
@client.tags_getListUser('user_id'=>@id)['who']['tags']['tag'].collect { |tag| tag }
|
360
|
+
end
|
361
|
+
|
362
|
+
# Implements flickr.photos.getContactsPublicPhotos and flickr.photos.getContactsPhotos
|
363
|
+
def contactsPhotos
|
364
|
+
@client.photos_request('photos.getContactsPublicPhotos', 'user_id' => @id)
|
365
|
+
end
|
366
|
+
|
367
|
+
def to_s
|
368
|
+
@name
|
369
|
+
end
|
370
|
+
|
371
|
+
|
372
|
+
|
373
|
+
private
|
374
|
+
|
375
|
+
# Implements flickr.people.getInfo, flickr.urls.getUserPhotos, and flickr.urls.getUserProfile
|
376
|
+
def getInfo
|
377
|
+
info = @client.people_getInfo('user_id'=>@id)['person']
|
378
|
+
@username = info['username']
|
379
|
+
@name = info['realname']
|
380
|
+
@location = info['location']
|
381
|
+
@count = info['photos']['count']
|
382
|
+
@firstdate = info['photos']['firstdate']
|
383
|
+
@firstdatetaken = info['photos']['firstdatetaken']
|
384
|
+
self
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
|
389
|
+
class Photo
|
390
|
+
|
391
|
+
attr_reader :id, :client, :title
|
392
|
+
|
393
|
+
def initialize(id=nil, api_key=nil, extra_params={})
|
394
|
+
@id = id
|
395
|
+
@api_key = api_key
|
396
|
+
extra_params.each { |k,v| self.instance_variable_set("@#{k}", v) } # convert extra_params into instance variables
|
397
|
+
@client = Flickr.new @api_key
|
398
|
+
end
|
399
|
+
|
400
|
+
# Allows access to all photos instance variables through hash like
|
401
|
+
# interface, e.g. photo["datetaken"] returns @datetaken instance
|
402
|
+
# variable. Useful for accessing any weird and wonderful parameter
|
403
|
+
# that may have been returned by Flickr when finding the photo,
|
404
|
+
# e.g. those returned by the extras argument in
|
405
|
+
# flickr.people.getPublicPhotos
|
406
|
+
def [](param_name)
|
407
|
+
instance_variable_get("@#{param_name}")
|
408
|
+
end
|
409
|
+
|
410
|
+
def title
|
411
|
+
@title.nil? ? getInfo("title") : @title
|
412
|
+
end
|
413
|
+
|
414
|
+
# Returns the owner of the photo as a Flickr::User. If we have no info
|
415
|
+
# about the owner, we make an API call to get it. If we already have
|
416
|
+
# the owner's id, create a user based on that. Either way, we cache the
|
417
|
+
# result so we don't need to check again
|
418
|
+
def owner
|
419
|
+
case @owner
|
420
|
+
when Flickr::User
|
421
|
+
@owner
|
422
|
+
when String
|
423
|
+
@owner = Flickr::User.new(@owner, nil, nil, nil, @api_key)
|
424
|
+
else
|
425
|
+
getInfo("owner")
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def server
|
430
|
+
@server.nil? ? getInfo("server") : @server
|
431
|
+
end
|
432
|
+
|
433
|
+
def isfavorite
|
434
|
+
@isfavorite.nil? ? getInfo("isfavorite") : @isfavorite
|
435
|
+
end
|
436
|
+
|
437
|
+
def license
|
438
|
+
@license.nil? ? getInfo("license") : @license
|
439
|
+
end
|
440
|
+
|
441
|
+
def rotation
|
442
|
+
@rotation.nil? ? getInfo("rotation") : @rotation
|
443
|
+
end
|
444
|
+
|
445
|
+
def description
|
446
|
+
@description || getInfo("description")
|
447
|
+
end
|
448
|
+
|
449
|
+
def notes
|
450
|
+
@notes.nil? ? getInfo("notes") : @notes
|
451
|
+
end
|
452
|
+
|
453
|
+
# Returns the URL for the photo size page
|
454
|
+
# defaults to 'Medium'
|
455
|
+
# other valid sizes are in the VALID_SIZES hash
|
456
|
+
def size_url(size='Medium')
|
457
|
+
uri_for_photo_from_self(size) || sizes(size)['url']
|
458
|
+
end
|
459
|
+
|
460
|
+
# converts string or symbol size to a capitalized string
|
461
|
+
def normalize_size(size)
|
462
|
+
size ? size.to_s.capitalize : size
|
463
|
+
end
|
464
|
+
|
465
|
+
# the URL for the main photo page
|
466
|
+
# if getInfo has already been called, this will return the pretty url
|
467
|
+
#
|
468
|
+
# for historical reasons, an optional size can be given
|
469
|
+
# 'Medium' returns the regular url; any other size returns a size page
|
470
|
+
# use size_url instead
|
471
|
+
def url(size = nil)
|
472
|
+
if normalize_size(size) != 'Medium'
|
473
|
+
size_url(size)
|
474
|
+
else
|
475
|
+
@url || uri_for_photo_from_self
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# the 'pretty' url for a photo
|
480
|
+
# (if the user has set up a custom name)
|
481
|
+
# eg, http://flickr.com/photos/granth/2584402507/ instead of
|
482
|
+
# http://flickr.com/photos/23386158@N00/2584402507/
|
483
|
+
def pretty_url
|
484
|
+
@url || getInfo("pretty_url")
|
485
|
+
end
|
486
|
+
|
487
|
+
# Returns the URL for the image (default or any specified size)
|
488
|
+
def source(size='Medium')
|
489
|
+
image_source_uri_from_self(size) || sizes(size)['source']
|
490
|
+
end
|
491
|
+
|
492
|
+
# Returns the photo file data itself, in any specified size. Example: File.open(photo.title, 'w') { |f| f.puts photo.file }
|
493
|
+
def file(size='Medium')
|
494
|
+
Net::HTTP.get_response(URI.parse(source(size))).body
|
495
|
+
end
|
496
|
+
|
497
|
+
# Unique filename for the image, based on the Flickr NSID
|
498
|
+
def filename
|
499
|
+
"#{@id}.jpg"
|
500
|
+
end
|
501
|
+
|
502
|
+
# Implements flickr.photos.getContext
|
503
|
+
def context
|
504
|
+
context = @client.photos_getContext('photo_id'=>@id)
|
505
|
+
@previousPhoto = Photo.new(context['prevphoto'].delete('id'), @api_key, context['prevphoto']) if context['prevphoto']['id']!='0'
|
506
|
+
@nextPhoto = Photo.new(context['nextphoto'].delete('id'), @api_key, context['nextphoto']) if context['nextphoto']['id']!='0'
|
507
|
+
return [@previousPhoto, @nextPhoto]
|
508
|
+
end
|
509
|
+
|
510
|
+
# Implements flickr.photos.getExif
|
511
|
+
def exif
|
512
|
+
@client.photos_getExif('photo_id'=>@id)['photo']
|
513
|
+
end
|
514
|
+
|
515
|
+
# Implements flickr.photos.getPerms
|
516
|
+
def permissions
|
517
|
+
@client.photos_getPerms('photo_id'=>@id)['perms']
|
518
|
+
end
|
519
|
+
|
520
|
+
# Implements flickr.photos.getSizes
|
521
|
+
def sizes(size=nil)
|
522
|
+
size = normalize_size(size)
|
523
|
+
sizes = @client.photos_getSizes('photo_id'=>@id)['sizes']['size']
|
524
|
+
sizes = sizes.find{|asize| asize['label']==size} if size
|
525
|
+
return sizes
|
526
|
+
end
|
527
|
+
|
528
|
+
# flickr.tags.getListPhoto
|
529
|
+
def tags
|
530
|
+
@client.tags_getListPhoto('photo_id'=>@id)['photo']['tags']
|
531
|
+
end
|
532
|
+
|
533
|
+
# Implements flickr.photos.notes.add
|
534
|
+
def add_note(note)
|
535
|
+
end
|
536
|
+
|
537
|
+
# Implements flickr.photos.setDates
|
538
|
+
def dates=(dates)
|
539
|
+
end
|
540
|
+
|
541
|
+
# Implements flickr.photos.setPerms
|
542
|
+
def perms=(perms)
|
543
|
+
end
|
544
|
+
|
545
|
+
# Implements flickr.photos.setTags
|
546
|
+
def tags=(tags)
|
547
|
+
end
|
548
|
+
|
549
|
+
# Implements flickr.photos.setMeta
|
550
|
+
def title=(title)
|
551
|
+
end
|
552
|
+
def description=(title)
|
553
|
+
end
|
554
|
+
|
555
|
+
# Implements flickr.photos.addTags
|
556
|
+
def add_tag(tag)
|
557
|
+
end
|
558
|
+
|
559
|
+
# Implements flickr.photos.removeTag
|
560
|
+
def remove_tag(tag)
|
561
|
+
end
|
562
|
+
|
563
|
+
# Implements flickr.photos.transform.rotate
|
564
|
+
def rotate
|
565
|
+
end
|
566
|
+
|
567
|
+
# Implements flickr.blogs.postPhoto
|
568
|
+
def postToBlog(blog_id, title='', description='')
|
569
|
+
@client.blogs_postPhoto('photo_id'=>@id, 'title'=>title, 'description'=>description)
|
570
|
+
end
|
571
|
+
|
572
|
+
# Implements flickr.photos.notes.delete
|
573
|
+
def deleteNote(note_id)
|
574
|
+
end
|
575
|
+
|
576
|
+
# Implements flickr.photos.notes.edit
|
577
|
+
def editNote(note_id)
|
578
|
+
end
|
579
|
+
|
580
|
+
# Converts the Photo to a string by returning its title
|
581
|
+
def to_s
|
582
|
+
title
|
583
|
+
end
|
584
|
+
|
585
|
+
|
586
|
+
# unvlog
|
587
|
+
def media
|
588
|
+
@media || getInfo("media")
|
589
|
+
end
|
590
|
+
|
591
|
+
def secret
|
592
|
+
@secret || getInfo("secret")
|
593
|
+
end
|
594
|
+
|
595
|
+
|
596
|
+
private
|
597
|
+
|
598
|
+
# Implements flickr.photos.getInfo
|
599
|
+
def getInfo(attrib="")
|
600
|
+
return instance_variable_get("@#{attrib}") if @got_info
|
601
|
+
info = @client.photos_getInfo('photo_id'=>@id)['photo']
|
602
|
+
@got_info = true
|
603
|
+
info.each { |k,v| instance_variable_set("@#{k}", v)}
|
604
|
+
@media = info['media']
|
605
|
+
@secret = info['secret']
|
606
|
+
@owner = User.new(info['owner']['nsid'], info['owner']['username'], nil, nil, @api_key)
|
607
|
+
@tags = info['tags']['tag']
|
608
|
+
@notes = info['notes']['note']#.collect { |note| Note.new(note.id) }
|
609
|
+
@url = info['urls']['url']['content'] # assumes only one url
|
610
|
+
instance_variable_get("@#{attrib}")
|
611
|
+
end
|
612
|
+
|
613
|
+
# Builds source uri of image from params (often returned from other
|
614
|
+
# methods, e.g. User#photos). As specified at:
|
615
|
+
# http://www.flickr.com/services/api/misc.urls.html. If size is given
|
616
|
+
# should be one the keys in the VALID_SIZES hash, i.e.
|
617
|
+
# "Square", "Thumbnail", "Medium", "Large", "Original", "Small" (These
|
618
|
+
# are the values returned by flickr.photos.getSizes).
|
619
|
+
# If no size is given the uri for "Medium"-size image, i.e. with width
|
620
|
+
# of 500 is returned
|
621
|
+
# TODO: Handle "Original" size
|
622
|
+
def image_source_uri_from_self(size=nil)
|
623
|
+
return unless @farm&&@server&&@id&&@secret
|
624
|
+
s_size = VALID_SIZES[normalize_size(size)] # get the short letters array corresponding to the size
|
625
|
+
s_size = s_size&&s_size[0] # the first element of this array is used to build the source uri
|
626
|
+
if s_size.nil?
|
627
|
+
"http://farm#{@farm}.static.flickr.com/#{@server}/#{@id}_#{@secret}.jpg"
|
628
|
+
else
|
629
|
+
"http://farm#{@farm}.static.flickr.com/#{@server}/#{@id}_#{@secret}_#{s_size}.jpg"
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
# Builds uri of Flickr page for photo. By default returns the main
|
634
|
+
# page for the photo, but if passed a size will return the simplified
|
635
|
+
# flickr page featuring the given size of the photo
|
636
|
+
# TODO: Handle "Original" size
|
637
|
+
def uri_for_photo_from_self(size=nil)
|
638
|
+
return unless @owner&&@id
|
639
|
+
size = normalize_size(size)
|
640
|
+
s_size = VALID_SIZES[size] # get the short letters array corresponding to the size
|
641
|
+
s_size = s_size&&s_size[1] # the second element of this array is used to build the uri of the flickr page for this size
|
642
|
+
"http://www.flickr.com/photos/#{owner.id}/#{@id}" + (s_size ? "/sizes/#{s_size}/" : "")
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
# Todo:
|
647
|
+
# flickr.groups.pools.add
|
648
|
+
# flickr.groups.pools.getContext
|
649
|
+
# flickr.groups.pools.getGroups
|
650
|
+
# flickr.groups.pools.getPhotos
|
651
|
+
# flickr.groups.pools.remove
|
652
|
+
class Group
|
653
|
+
attr_reader :id, :client, :description, :name, :eighteenplus, :members, :online, :privacy, :url#, :chatid, :chatcount
|
654
|
+
|
655
|
+
def initialize(id_or_params_hash=nil, api_key=nil)
|
656
|
+
if id_or_params_hash.is_a?(Hash)
|
657
|
+
id_or_params_hash.each { |k,v| self.instance_variable_set("@#{k}", v) } # convert extra_params into instance variables
|
658
|
+
else
|
659
|
+
@id = id_or_params_hash
|
660
|
+
@api_key = api_key
|
661
|
+
@client = Flickr.new @api_key
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
# Implements flickr.groups.getInfo and flickr.urls.getGroup
|
666
|
+
# private, once we can call it as needed
|
667
|
+
def getInfo
|
668
|
+
info = @client.groups_getInfo('group_id'=>@id)['group']
|
669
|
+
@name = info['name']
|
670
|
+
@members = info['members']
|
671
|
+
@online = info['online']
|
672
|
+
@privacy = info['privacy']
|
673
|
+
# @chatid = info['chatid']
|
674
|
+
# @chatcount = info['chatcount']
|
675
|
+
@url = @client.urls_getGroup('group_id'=>@id)['group']['url']
|
676
|
+
self
|
677
|
+
end
|
678
|
+
|
679
|
+
end
|
680
|
+
|
681
|
+
# Todo:
|
682
|
+
# flickr.photosets.delete
|
683
|
+
# flickr.photosets.editMeta
|
684
|
+
# flickr.photosets.editPhotos
|
685
|
+
# flickr.photosets.getContext
|
686
|
+
# flickr.photosets.getInfo
|
687
|
+
# flickr.photosets.getPhotos
|
688
|
+
class Photoset
|
689
|
+
|
690
|
+
attr_reader :id, :client, :owner, :primary, :photos, :title, :description, :url
|
691
|
+
|
692
|
+
def initialize(id=nil, api_key=nil)
|
693
|
+
@id = id
|
694
|
+
@api_key = api_key
|
695
|
+
@client = Flickr.new @api_key
|
696
|
+
end
|
697
|
+
|
698
|
+
# Implements flickr.photosets.getInfo
|
699
|
+
# private, once we can call it as needed
|
700
|
+
def getInfo
|
701
|
+
info = @client.photosets_getInfo('photoset_id'=>@id)['photoset']
|
702
|
+
@owner = User.new(info['owner'], nil, nil, nil, @api_key)
|
703
|
+
@primary = info['primary']
|
704
|
+
@photos = info['photos']
|
705
|
+
@title = info['title']
|
706
|
+
@description = info['description']
|
707
|
+
@url = "http://www.flickr.com/photos/#{@owner.getInfo.username}/sets/#{@id}/"
|
708
|
+
self
|
709
|
+
end
|
710
|
+
|
711
|
+
end
|
712
|
+
|
713
|
+
end
|