flickollage 0.0.3

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0bf1524178358a9af7ccece83dff0511d631733f
4
+ data.tar.gz: 7b52460521ecd5ec1633f780b15c525ec9651afe
5
+ SHA512:
6
+ metadata.gz: 2acf6edde06c4bc7a5326ba2401949c1f564d9fada5236cc6f0d90ac05c963606788d564fba590bd83dd0af853a9116586747ab6796ba42187277140e40186b8
7
+ data.tar.gz: 05fdea90eb41ebd282ab9c1ee32c355de1baceeab78dd93b138a35b0516cb76f62c9919de0cc9a63137aa2ada5f8fed2fd1c7eac9ad3db5d7417268c69a151a2
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ .env
3
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format doc
data/.rubocop.yml ADDED
@@ -0,0 +1,12 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.2
3
+
4
+ Style/Documentation:
5
+ Enabled: false
6
+
7
+ Metrics/LineLength:
8
+ Max: 100
9
+
10
+ Metrics/BlockLength:
11
+ Exclude:
12
+ - spec/**/*
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.0
5
+ - 2.1
6
+ - 2.2
7
+
8
+ before_script:
9
+ - sudo apt-get update
10
+ - sudo apt-get install imagemagick libmagickcore-dev libmagickwand-dev
11
+ - sudo apt-get install -qq graphicsmagick
12
+
13
+ script:
14
+ - rspec
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # Flickollage [![Gem Version](https://badge.fury.io/rb/flickollage.svg)](https://badge.fury.io/rb/flickollage) [![Build Status](https://travis-ci.org/alexandrz/flickollage.svg?branch=master)](https://travis-ci.org/alexandrz/flickollage)
2
+
3
+ A simple command-line tool that accepts a list of words as arguments and generates
4
+ a collage grid from ten top-rated images found on Flickr using the provided keywords.
5
+
6
+ ## Installation
7
+
8
+ You can install Flickollage from rubygems. It requires Ruby version >= 2.0 and
9
+ ImageMagick or GraphicsMagick command-line tool.
10
+
11
+ $ gem install flickollage
12
+
13
+ ## Flickr access key
14
+
15
+ You need to provide Flickr access key and shared secret. It can be done using environment
16
+ variables `FLICKR_API_KEY` and `FLICKR_SHARED_SECRET` or command-line options
17
+ `--flickr-api-key` and `--flickr-shared-key`.
18
+
19
+ ## Usage
20
+
21
+ $ flickollage generate -n 2 --rows=1 --cols=2 --width=300 --height=200 Berlin 'New York'
22
+
23
+ ![Cities Collage](spec/fixtures/cities.png)
24
+
25
+ $ flickollage generate --dict=spec/fixtures/mountains --output mountains.png
26
+
27
+ ![Mountains Collage](spec/fixtures/mountains.png)
data/bin/flickollage ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'flickollage'
5
+
6
+ Dotenv.load
7
+
8
+ Flickollage::CLI.start(ARGV)
@@ -0,0 +1,26 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'flickollage'
3
+ s.version = '0.0.3'
4
+ s.date = '2017-03-05'
5
+ s.summary = 'Flickollage Collage Generator'
6
+ s.description = 'Flickollage is a simple command line tool for generating collages'
7
+ s.authors = ['Aleksandr Zykov']
8
+ s.email = 'alexandrz@gmail.com'
9
+ s.homepage = 'https://github.com/alexandrz/flickollage'
10
+ s.license = 'MIT'
11
+
12
+ s.files = `git ls-files`.split("\n")
13
+ s.test_files = `git ls-files -- spec/*`.split("\n")
14
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
15
+ s.require_paths = ['lib']
16
+
17
+ s.add_dependency 'thor', '~> 0.19'
18
+ s.add_dependency 'flickraw', '~> 0.9'
19
+ s.add_dependency 'mini_magick', '~> 4.6'
20
+
21
+ s.add_development_dependency 'rspec'
22
+ s.add_development_dependency 'dotenv'
23
+ s.add_development_dependency 'vcr'
24
+ s.add_development_dependency 'webmock'
25
+ s.add_development_dependency 'rubocop', '~> 0.47.1'
26
+ end
@@ -0,0 +1,44 @@
1
+ require 'thor'
2
+ require 'dotenv'
3
+ require 'logger'
4
+
5
+ # Flickollage Command Line Interface
6
+ module Flickollage
7
+ class CLI < ::Thor
8
+ include Logger
9
+
10
+ desc 'generate [LIST OF WORDS]', 'Generate collage from the list of words'
11
+ option :dict,
12
+ type: :string, aliases: '-d', default: Dictionary.default_dict_path,
13
+ desc: 'Path of the dictionatry file'
14
+ option :output,
15
+ type: :string, aliases: '-o', default: 'collage.png',
16
+ desc: 'Output image file name'
17
+ option :flickr_api_key,
18
+ type: :string,
19
+ desc: 'Flickr API Key, can also be set using environment variable'
20
+ option :flickr_shared_secret,
21
+ type: :string,
22
+ desc: 'Flickr Shared Secret, can also be set using environment variable'
23
+ option :number, type: :numeric, aliases: '-n', default: 10
24
+ option :rows, type: :numeric, aliases: '-r', default: 5
25
+ option :cols, type: :numeric, aliases: '-c', default: 2
26
+ option :width, type: :numeric, aliases: '-w', default: 200
27
+ option :height, type: :numeric, aliases: '-h', default: 150
28
+ option :verbose, type: :boolean, aliases: '-v'
29
+ long_desc <<-LONGDESC
30
+ `flickollage generate dolomites annapurna` will generate a photo collage.
31
+
32
+ You can provide flickr api key and shared secret using options described before
33
+ or environment variables `FLICKR_API_KEY` and `FLICKR_SHARED_SECRET`.
34
+ LONGDESC
35
+ def generate(*words)
36
+ Flickollage.init_logger(options)
37
+ return unless Flickollage.configure_flickraw(options)
38
+ Flickollage::Collage.new(words, options).generate_collage
39
+ rescue Flickollage::Error => e
40
+ logger.error(e.message)
41
+ logger.debug(e.inspect)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,80 @@
1
+ module Flickollage
2
+ class Collage
3
+ include Logger
4
+ class Error < ::Flickollage::Error; end
5
+
6
+ attr_reader :dictionary
7
+ attr_reader :words
8
+ attr_reader :options
9
+ attr_reader :images
10
+
11
+ RETRY_LIMIT = 10
12
+
13
+ def initialize(words, options)
14
+ @words = words
15
+ @options = options
16
+
17
+ init_dictionary
18
+ load_images
19
+ download_images
20
+ crop_images(options[:width], options[:height])
21
+ end
22
+
23
+ def generate_collage(path = nil)
24
+ path ||= options[:output]
25
+ MiniMagick::Tool::Montage.new do |montage|
26
+ images.each { |image| montage << image.image.path }
27
+
28
+ montage.geometry "#{options[:width]}x#{options[:height]}+0+0"
29
+ montage.tile "#{options[:cols]}x#{options[:rows]}"
30
+ montage.background 'black'
31
+
32
+ montage << path
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def init_dictionary
39
+ @dictionary = Dictionary.new(options[:dict])
40
+ @dictionary.append(words)
41
+ rescue Flickollage::Dictionary::Error
42
+ @dictionary = Dictionary.new(words)
43
+ end
44
+
45
+ def download_images
46
+ images.each(&:download)
47
+ end
48
+
49
+ def crop_images(width, height)
50
+ images.each do |image|
51
+ image.crop(width, height)
52
+ end
53
+ end
54
+
55
+ def load_images
56
+ @images = []
57
+ options[:number].times do
58
+ @images << load_image
59
+ end
60
+ end
61
+
62
+ def load_image(attempt = 1)
63
+ word = dictionary.pop
64
+ not_enought_words unless word
65
+ Image.new(word)
66
+ rescue Flickollage::Image::Error
67
+ too_many_attempts if attempt == RETRY_LIMIT
68
+ load_image(attempt + 1)
69
+ end
70
+
71
+ def not_enought_words
72
+ raise Flickollage::Error,
73
+ 'Not enought words. Please, specify more words or provide a bigger dictionary.'
74
+ end
75
+
76
+ def too_many_attempts
77
+ raise Flickollage::Error, 'Could not load images. Please, try later.'
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,47 @@
1
+ module Flickollage
2
+ class Dictionary
3
+ class Error < ::Flickollage::Error; end
4
+
5
+ MAX_DICT_LENGTH = 1_500_000
6
+
7
+ COMMON_DICT_PATHS = %w(
8
+ /usr/share/dict/words
9
+ /usr/dict/words
10
+ ).freeze
11
+
12
+ attr_reader :words
13
+
14
+ def initialize(path_or_words)
15
+ @words = []
16
+ load_from_file(path_or_words) if path_or_words.is_a?(String)
17
+ @words = path_or_words.reverse if path_or_words.is_a?(Array)
18
+ end
19
+
20
+ def pop
21
+ @words.pop
22
+ end
23
+
24
+ def append(words)
25
+ @words += words.reverse
26
+ end
27
+
28
+ private
29
+
30
+ def load_from_file(path)
31
+ File.foreach(path).with_index do |line, i|
32
+ break if i >= MAX_DICT_LENGTH
33
+ line = line.chop
34
+ @words << line unless line.empty?
35
+ end
36
+ @words.shuffle!
37
+ rescue Errno::ENOENT
38
+ raise Error, 'Dictionary file not found'
39
+ end
40
+
41
+ class << self
42
+ def default_dict_path
43
+ COMMON_DICT_PATHS.find { |path| File.exist?(path) } || COMMON_DICT_PATHS.first
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,45 @@
1
+ module Flickollage
2
+ class Image
3
+ include Logger
4
+ class Error < ::Flickollage::Error; end
5
+
6
+ attr_reader :word
7
+ attr_reader :url
8
+ attr_accessor :image
9
+
10
+ def initialize(word)
11
+ @word = word
12
+ search_on_flickr(word)
13
+ end
14
+
15
+ def download
16
+ logger.debug("Downloading an image: #{url}")
17
+ @image = MiniMagick::Image.open(url)
18
+ file_not_found unless @image
19
+ @image
20
+ end
21
+
22
+ def crop(width, height)
23
+ image.combine_options do |b|
24
+ b.resize "#{width}x#{height}^"
25
+ b.gravity 'Center'
26
+ b.extent "#{width}x#{height}"
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def file_not_found
33
+ raise Error, "Failed to load an image for keyword '#{word}'."
34
+ end
35
+
36
+ def search_on_flickr(word)
37
+ photo = flickr.photos.search(tags: word, sort: 'interestingness-desc', per_page: 1)[0]
38
+ raise Error, 'Could not find an image using this keyword' unless photo
39
+ @url = FlickRaw.url_b(photo)
40
+ logger.debug("Found an image for keyword '#{word}': #{@url}")
41
+ rescue FlickRaw::FailedResponse
42
+ raise ::Flickollage::Error, 'Invalid Flickr API key'
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ module Flickollage
2
+ module Logger
3
+ def logger
4
+ Flickollage.logger
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ require 'flickraw'
2
+ require 'mini_magick'
3
+
4
+ module Flickollage
5
+ class Error < StandardError; end
6
+ class << self
7
+ attr_accessor :logger
8
+
9
+ def init_logger(options = {})
10
+ Flickollage.logger = ::Logger.new(STDOUT).tap do |logger|
11
+ logger.level = options[:verbose] ? ::Logger::DEBUG : ::Logger::INFO
12
+ logger.formatter = proc do |_severity, _datetime, _progname, msg|
13
+ "#{msg}\n"
14
+ end
15
+ end
16
+ end
17
+
18
+ def configure_flickraw(options)
19
+ FlickRaw.api_key = ENV['FLICKR_API_KEY'] || options[:flickr_api_key]
20
+ FlickRaw.shared_secret = ENV['FLICKR_SHARED_SECRET'] || options[:flickr_shared_secret]
21
+ return true if FlickRaw.api_key && FlickRaw.shared_secret
22
+ logger.error 'Flickr configuration is not provided.'
23
+ false
24
+ end
25
+ end
26
+ end
27
+
28
+ require 'flickollage/logger.rb'
29
+ require 'flickollage/dictionary.rb'
30
+ require 'flickollage/image.rb'
31
+ require 'flickollage/collage.rb'
32
+ require 'flickollage/cli.rb'
Binary file
Binary file
@@ -0,0 +1,24 @@
1
+ Mont Blanc
2
+ Monte Rosa
3
+ Liskamm
4
+ Weisshorn
5
+ Matterhorn
6
+ Dent Blanche
7
+ Grand Combin
8
+ Finsteraarhorn
9
+ Zinalrothorn
10
+ Grandes Jorasses
11
+
12
+
13
+ Alphubel
14
+ Rimpfischhorn
15
+ Aletschhorn
16
+ Strahlhorn
17
+ Dent d'Hérens
18
+ Breithorn
19
+ Jungfrau
20
+ Aiguille Verte
21
+ Mönch
22
+ Barre des Écrins
23
+ Schreckhorn
24
+ Ober Gabelhorn
Binary file
Binary file
@@ -0,0 +1,112 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://api.flickr.com/services/rest/
6
+ body:
7
+ encoding: US-ASCII
8
+ string: method=flickr.reflection.getMethods&format=json&nojsoncallback=1
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - FlickRaw/0.9.9
16
+ Content-Type:
17
+ - application/x-www-form-urlencoded
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Date:
24
+ - Sun, 05 Mar 2017 11:41:25 GMT
25
+ Content-Type:
26
+ - application/json
27
+ Content-Length:
28
+ - '1438'
29
+ P3p:
30
+ - policyref="https://policies.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM
31
+ DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND
32
+ PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
33
+ X-Content-Type-Options:
34
+ - nosniff
35
+ Cache-Control:
36
+ - private
37
+ X-Served-By:
38
+ - www245.flickr.bf1.yahoo.com
39
+ X-Frame-Options:
40
+ - SAMEORIGIN
41
+ Vary:
42
+ - Accept-Encoding
43
+ Age:
44
+ - '0'
45
+ Via:
46
+ - http/1.1 fts101.flickr.bf1.yahoo.com (ApacheTrafficServer [cMsSf ]), http/1.1
47
+ e20.ycpi.lob.yahoo.com (ApacheTrafficServer [cMsSf ])
48
+ Server:
49
+ - ATS
50
+ Connection:
51
+ - keep-alive
52
+ body:
53
+ encoding: ASCII-8BIT
54
+ string: '{"methods":{"method":[{"_content":"flickr.activity.userComments"},{"_content":"flickr.activity.userPhotos"},{"_content":"flickr.auth.checkToken"},{"_content":"flickr.auth.getFrob"},{"_content":"flickr.auth.getFullToken"},{"_content":"flickr.auth.getToken"},{"_content":"flickr.auth.oauth.checkToken"},{"_content":"flickr.auth.oauth.getAccessToken"},{"_content":"flickr.blogs.getList"},{"_content":"flickr.blogs.getServices"},{"_content":"flickr.blogs.postPhoto"},{"_content":"flickr.cameras.getBrandModels"},{"_content":"flickr.cameras.getBrands"},{"_content":"flickr.collections.getInfo"},{"_content":"flickr.collections.getTree"},{"_content":"flickr.commons.getInstitutions"},{"_content":"flickr.contacts.getList"},{"_content":"flickr.contacts.getListRecentlyUploaded"},{"_content":"flickr.contacts.getPublicList"},{"_content":"flickr.contacts.getTaggingSuggestions"},{"_content":"flickr.favorites.add"},{"_content":"flickr.favorites.getContext"},{"_content":"flickr.favorites.getList"},{"_content":"flickr.favorites.getPublicList"},{"_content":"flickr.favorites.remove"},{"_content":"flickr.galleries.addPhoto"},{"_content":"flickr.galleries.create"},{"_content":"flickr.galleries.editMeta"},{"_content":"flickr.galleries.editPhoto"},{"_content":"flickr.galleries.editPhotos"},{"_content":"flickr.galleries.getInfo"},{"_content":"flickr.galleries.getList"},{"_content":"flickr.galleries.getListForPhoto"},{"_content":"flickr.galleries.getPhotos"},{"_content":"flickr.groups.browse"},{"_content":"flickr.groups.discuss.replies.add"},{"_content":"flickr.groups.discuss.replies.delete"},{"_content":"flickr.groups.discuss.replies.edit"},{"_content":"flickr.groups.discuss.replies.getInfo"},{"_content":"flickr.groups.discuss.replies.getList"},{"_content":"flickr.groups.discuss.topics.add"},{"_content":"flickr.groups.discuss.topics.getInfo"},{"_content":"flickr.groups.discuss.topics.getList"},{"_content":"flickr.groups.getInfo"},{"_content":"flickr.groups.join"},{"_content":"flickr.groups.joinRequest"},{"_content":"flickr.groups.leave"},{"_content":"flickr.groups.members.getList"},{"_content":"flickr.groups.pools.add"},{"_content":"flickr.groups.pools.getContext"},{"_content":"flickr.groups.pools.getGroups"},{"_content":"flickr.groups.pools.getPhotos"},{"_content":"flickr.groups.pools.remove"},{"_content":"flickr.groups.search"},{"_content":"flickr.interestingness.getList"},{"_content":"flickr.machinetags.getNamespaces"},{"_content":"flickr.machinetags.getPairs"},{"_content":"flickr.machinetags.getPredicates"},{"_content":"flickr.machinetags.getRecentValues"},{"_content":"flickr.machinetags.getValues"},{"_content":"flickr.panda.getList"},{"_content":"flickr.panda.getPhotos"},{"_content":"flickr.people.findByEmail"},{"_content":"flickr.people.findByUsername"},{"_content":"flickr.people.getGroups"},{"_content":"flickr.people.getInfo"},{"_content":"flickr.people.getLimits"},{"_content":"flickr.people.getPhotos"},{"_content":"flickr.people.getPhotosOf"},{"_content":"flickr.people.getPublicGroups"},{"_content":"flickr.people.getPublicPhotos"},{"_content":"flickr.people.getUploadStatus"},{"_content":"flickr.photos.addTags"},{"_content":"flickr.photos.comments.addComment"},{"_content":"flickr.photos.comments.deleteComment"},{"_content":"flickr.photos.comments.editComment"},{"_content":"flickr.photos.comments.getList"},{"_content":"flickr.photos.comments.getRecentForContacts"},{"_content":"flickr.photos.delete"},{"_content":"flickr.photos.geo.batchCorrectLocation"},{"_content":"flickr.photos.geo.correctLocation"},{"_content":"flickr.photos.geo.getLocation"},{"_content":"flickr.photos.geo.getPerms"},{"_content":"flickr.photos.geo.photosForLocation"},{"_content":"flickr.photos.geo.removeLocation"},{"_content":"flickr.photos.geo.setContext"},{"_content":"flickr.photos.geo.setLocation"},{"_content":"flickr.photos.geo.setPerms"},{"_content":"flickr.photos.getAllContexts"},{"_content":"flickr.photos.getContactsPhotos"},{"_content":"flickr.photos.getContactsPublicPhotos"},{"_content":"flickr.photos.getContext"},{"_content":"flickr.photos.getCounts"},{"_content":"flickr.photos.getExif"},{"_content":"flickr.photos.getFavorites"},{"_content":"flickr.photos.getInfo"},{"_content":"flickr.photos.getNotInSet"},{"_content":"flickr.photos.getPerms"},{"_content":"flickr.photos.getPopular"},{"_content":"flickr.photos.getRecent"},{"_content":"flickr.photos.getSizes"},{"_content":"flickr.photos.getUntagged"},{"_content":"flickr.photos.getWithGeoData"},{"_content":"flickr.photos.getWithoutGeoData"},{"_content":"flickr.photos.licenses.getInfo"},{"_content":"flickr.photos.licenses.setLicense"},{"_content":"flickr.photos.notes.add"},{"_content":"flickr.photos.notes.delete"},{"_content":"flickr.photos.notes.edit"},{"_content":"flickr.photos.people.add"},{"_content":"flickr.photos.people.delete"},{"_content":"flickr.photos.people.deleteCoords"},{"_content":"flickr.photos.people.editCoords"},{"_content":"flickr.photos.people.getList"},{"_content":"flickr.photos.recentlyUpdated"},{"_content":"flickr.photos.removeTag"},{"_content":"flickr.photos.search"},{"_content":"flickr.photos.setContentType"},{"_content":"flickr.photos.setDates"},{"_content":"flickr.photos.setMeta"},{"_content":"flickr.photos.setPerms"},{"_content":"flickr.photos.setSafetyLevel"},{"_content":"flickr.photos.setTags"},{"_content":"flickr.photos.suggestions.approveSuggestion"},{"_content":"flickr.photos.suggestions.getList"},{"_content":"flickr.photos.suggestions.rejectSuggestion"},{"_content":"flickr.photos.suggestions.removeSuggestion"},{"_content":"flickr.photos.suggestions.suggestLocation"},{"_content":"flickr.photos.transform.rotate"},{"_content":"flickr.photos.upload.checkTickets"},{"_content":"flickr.photosets.addPhoto"},{"_content":"flickr.photosets.comments.addComment"},{"_content":"flickr.photosets.comments.deleteComment"},{"_content":"flickr.photosets.comments.editComment"},{"_content":"flickr.photosets.comments.getList"},{"_content":"flickr.photosets.create"},{"_content":"flickr.photosets.delete"},{"_content":"flickr.photosets.editMeta"},{"_content":"flickr.photosets.editPhotos"},{"_content":"flickr.photosets.getContext"},{"_content":"flickr.photosets.getInfo"},{"_content":"flickr.photosets.getList"},{"_content":"flickr.photosets.getPhotos"},{"_content":"flickr.photosets.orderSets"},{"_content":"flickr.photosets.removePhoto"},{"_content":"flickr.photosets.removePhotos"},{"_content":"flickr.photosets.reorderPhotos"},{"_content":"flickr.photosets.setPrimaryPhoto"},{"_content":"flickr.places.find"},{"_content":"flickr.places.findByLatLon"},{"_content":"flickr.places.getChildrenWithPhotosPublic"},{"_content":"flickr.places.getInfo"},{"_content":"flickr.places.getInfoByUrl"},{"_content":"flickr.places.getPlaceTypes"},{"_content":"flickr.places.getShapeHistory"},{"_content":"flickr.places.getTopPlacesList"},{"_content":"flickr.places.placesForBoundingBox"},{"_content":"flickr.places.placesForContacts"},{"_content":"flickr.places.placesForTags"},{"_content":"flickr.places.placesForUser"},{"_content":"flickr.places.resolvePlaceId"},{"_content":"flickr.places.resolvePlaceURL"},{"_content":"flickr.places.tagsForPlace"},{"_content":"flickr.prefs.getContentType"},{"_content":"flickr.prefs.getGeoPerms"},{"_content":"flickr.prefs.getHidden"},{"_content":"flickr.prefs.getPrivacy"},{"_content":"flickr.prefs.getSafetyLevel"},{"_content":"flickr.profile.getProfile"},{"_content":"flickr.push.getSubscriptions"},{"_content":"flickr.push.getTopics"},{"_content":"flickr.push.subscribe"},{"_content":"flickr.push.unsubscribe"},{"_content":"flickr.reflection.getMethodInfo"},{"_content":"flickr.reflection.getMethods"},{"_content":"flickr.stats.getCollectionDomains"},{"_content":"flickr.stats.getCollectionReferrers"},{"_content":"flickr.stats.getCollectionStats"},{"_content":"flickr.stats.getCSVFiles"},{"_content":"flickr.stats.getPhotoDomains"},{"_content":"flickr.stats.getPhotoReferrers"},{"_content":"flickr.stats.getPhotosetDomains"},{"_content":"flickr.stats.getPhotosetReferrers"},{"_content":"flickr.stats.getPhotosetStats"},{"_content":"flickr.stats.getPhotoStats"},{"_content":"flickr.stats.getPhotostreamDomains"},{"_content":"flickr.stats.getPhotostreamReferrers"},{"_content":"flickr.stats.getPhotostreamStats"},{"_content":"flickr.stats.getPopularPhotos"},{"_content":"flickr.stats.getTotalViews"},{"_content":"flickr.tags.getClusterPhotos"},{"_content":"flickr.tags.getClusters"},{"_content":"flickr.tags.getHotList"},{"_content":"flickr.tags.getListPhoto"},{"_content":"flickr.tags.getListUser"},{"_content":"flickr.tags.getListUserPopular"},{"_content":"flickr.tags.getListUserRaw"},{"_content":"flickr.tags.getMostFrequentlyUsed"},{"_content":"flickr.tags.getRelated"},{"_content":"flickr.test.echo"},{"_content":"flickr.test.login"},{"_content":"flickr.test.null"},{"_content":"flickr.urls.getGroup"},{"_content":"flickr.urls.getUserPhotos"},{"_content":"flickr.urls.getUserProfile"},{"_content":"flickr.urls.lookupGallery"},{"_content":"flickr.urls.lookupGroup"},{"_content":"flickr.urls.lookupUser"}]},"stat":"ok"}'
55
+ http_version:
56
+ recorded_at: Sun, 05 Mar 2017 11:41:25 GMT
57
+ - request:
58
+ method: post
59
+ uri: https://api.flickr.com/services/rest/
60
+ body:
61
+ encoding: US-ASCII
62
+ string: tags=dolomites&sort=interestingness-desc&per_page=1&method=flickr.photos.search&format=json&nojsoncallback=1
63
+ headers:
64
+ Accept-Encoding:
65
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
66
+ Accept:
67
+ - "*/*"
68
+ User-Agent:
69
+ - FlickRaw/0.9.9
70
+ Content-Type:
71
+ - application/x-www-form-urlencoded
72
+ response:
73
+ status:
74
+ code: 200
75
+ message: OK
76
+ headers:
77
+ Date:
78
+ - Sun, 05 Mar 2017 11:41:25 GMT
79
+ Content-Type:
80
+ - application/json
81
+ Content-Length:
82
+ - '196'
83
+ P3p:
84
+ - policyref="https://policies.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM
85
+ DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND
86
+ PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
87
+ X-Content-Type-Options:
88
+ - nosniff
89
+ Cache-Control:
90
+ - private
91
+ X-Served-By:
92
+ - bm-www930.flickr.bf1.yahoo.com
93
+ X-Frame-Options:
94
+ - SAMEORIGIN
95
+ Vary:
96
+ - Accept-Encoding
97
+ Age:
98
+ - '0'
99
+ Via:
100
+ - http/1.1 fts110.flickr.bf1.yahoo.com (ApacheTrafficServer [cMsSf ]), http/1.1
101
+ e22.ycpi.lob.yahoo.com (ApacheTrafficServer [cMsSf ])
102
+ Server:
103
+ - ATS
104
+ Connection:
105
+ - keep-alive
106
+ body:
107
+ encoding: ASCII-8BIT
108
+ string: '{"photos":{"page":1,"pages":159876,"perpage":1,"total":"159876","photo":[{"id":"33209118996","owner":"48059305@N03","secret":"1e1d0a66ee","server":"758","farm":1,"title":"Magic
109
+ dawn at Lusia alp","ispublic":1,"isfriend":0,"isfamily":0}]},"stat":"ok"}'
110
+ http_version:
111
+ recorded_at: Sun, 05 Mar 2017 11:41:25 GMT
112
+ recorded_with: VCR 2.9.2