aviary 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +21 -0
  4. data/README.md +110 -0
  5. data/Rakefile +10 -0
  6. data/aviary.gemspec +32 -0
  7. data/bin/aviary +87 -0
  8. data/generator/_assets/aviary.css +95 -0
  9. data/generator/_assets/aviary.js +38 -0
  10. data/generator/_assets/loader.gif +0 -0
  11. data/generator/template.erb +45 -0
  12. data/lib/aviary.rb +28 -0
  13. data/lib/aviary/configuration.rb +36 -0
  14. data/lib/aviary/generator.rb +40 -0
  15. data/lib/aviary/image_host.rb +74 -0
  16. data/lib/aviary/image_host/flickr.rb +53 -0
  17. data/lib/aviary/image_host/plixi.rb +27 -0
  18. data/lib/aviary/image_host/twitpic.rb +13 -0
  19. data/lib/aviary/image_host/yfrog.rb +13 -0
  20. data/lib/aviary/page.rb +26 -0
  21. data/lib/aviary/paginator.rb +54 -0
  22. data/lib/aviary/search.rb +34 -0
  23. data/lib/aviary/site.rb +52 -0
  24. data/lib/aviary/version.rb +3 -0
  25. data/test/aviary/configuration_test.rb +30 -0
  26. data/test/aviary/generator_test.rb +33 -0
  27. data/test/aviary/image_host/flickr_test.rb +60 -0
  28. data/test/aviary/image_host/plixi_test.rb +30 -0
  29. data/test/aviary/image_host/twitpic_test.rb +15 -0
  30. data/test/aviary/image_host/yfrog_test.rb +15 -0
  31. data/test/aviary/image_host_test.rb +65 -0
  32. data/test/aviary/page_test.rb +29 -0
  33. data/test/aviary/paginator_test.rb +48 -0
  34. data/test/aviary/search_test.rb +43 -0
  35. data/test/aviary/site_test.rb +66 -0
  36. data/test/fixtures/flickr.xml +19 -0
  37. data/test/fixtures/plixi.xml +1 -0
  38. data/test/fixtures/source/_assets/static +0 -0
  39. data/test/fixtures/source/_assets/subdir/static +0 -0
  40. data/test/fixtures/source/template.erb +5 -0
  41. data/test/fixtures/twitter.json +1 -0
  42. data/test/helper.rb +9 -0
  43. metadata +271 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .bundle/
2
+ Gemfile.lock
3
+ pkg/
4
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2011 Tate Johnson <tate@tatey.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # Aviary
2
+
3
+ Aviary generates a static photo gallery using Twitter hashtags.
4
+
5
+ Twitter is a fantastic resource for discovering photos of events as they unfold. Searching by hastag means you have to do the filtering. Commentary and relinking drown new and interesting photos. In the days the water rose during the 2011 Brisbane floods I wished there was a way to see all the photos without the noise. Now there is.
6
+
7
+ See the wiki for a [listing of galleries](https://github.com/tatey/aviary/wiki/galleries).
8
+
9
+ ## Getting Started
10
+
11
+ Install Aviary at the command prompt if you haven't yet
12
+
13
+ gem install aviary
14
+
15
+ At the command prompt, create a new Aviary template
16
+
17
+ aviary new bird
18
+
19
+ Change directory and for search tweets tagged with `bird` that have photos
20
+
21
+ cd bird/
22
+ aviary search bird
23
+
24
+ Build the static photo gallery
25
+
26
+ aviary build
27
+
28
+ Preview
29
+
30
+ cd _site/
31
+ gem install asdf
32
+ asdf .
33
+ open http://localhost:9292/index.htm
34
+
35
+ ## Dependencies
36
+
37
+ * Ruby 1.8.7, 1.9.2
38
+ * SQLite3
39
+
40
+ ### Runtime
41
+
42
+ * Base58
43
+ * DataMapper (Core, SQLite Adapter, Migrations and Validations)
44
+ * Nokoigir
45
+ * Twitter
46
+
47
+ ### Development
48
+
49
+ * Bundler
50
+ * MiniTest
51
+ * Webmock
52
+
53
+ ## Customising the Template
54
+
55
+ When you create a new aviary you'll notice `_assets/` and `template.erb` are automatically generated for you. Aviary uses these files and directories to generate the static photo gallery.
56
+
57
+ Linking back to Aviary is not required, although it is appreciated.
58
+
59
+ ### template.erb
60
+
61
+ Pages are plain ERB templates. You get access to the photos and pagination for the current page. You can control the number of photos per page by using `aviary build --per-page=NUM`.
62
+
63
+ `image_hosts` is a collection of photos for the current page.
64
+
65
+ <% image_hosts.each do |image_host| %>
66
+ <a href="<%= image_host.href %>"><img src="<%= image_host.src %>"></a>
67
+ <p><%= image_host.status.from_user %> said <%= h image_host.status.text %></p>
68
+ <% end >
69
+
70
+ `paginator` is for finding where you are.
71
+
72
+ <% if paginator.prev_page? %>
73
+ <a href="/page<%= paginator.prev_page %>/">Previous</a>
74
+ <% end %>
75
+ <% if paginator.next_page? %>
76
+ <a href="/page<%= paginator.next_page %>/">Next</a>
77
+ <% end %>
78
+
79
+ `h` escapes content which may be unsafe, such as a user's status text.
80
+
81
+ <%= h "<script>" %>
82
+
83
+ ...becomes
84
+
85
+ &lt;script&gt;
86
+
87
+ ### _assets
88
+
89
+ Anything inside the `_assets` directory is recursively copied into the root of the destination directory.
90
+
91
+ Examples:
92
+
93
+ ~/bird/_assets/aviary.css -> ~/bird/_site/aviary.css
94
+ ~/bird/_assets/images/status.png -> ~/bird/_site/images/status.png
95
+
96
+ Be careful not to name any of your assets with the following names:
97
+
98
+ * _assets/index.htm
99
+ * _assets/page1
100
+ * _assets/page2
101
+ * ...
102
+ * _assets/pageN
103
+
104
+ ## Why the Name?
105
+
106
+ Aviary is defined as "A large cage for keeping birds in". Replace cage with "photo gallery" and birds with "tweets".
107
+
108
+ ## Copyright
109
+
110
+ Copyright © 2010 Tate Johnson. Aviary is released under the MIT license. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'test'
7
+ test.pattern = 'test/**/*_test.rb'
8
+ end
9
+
10
+ task :default => :test
data/aviary.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/aviary/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'aviary'
6
+ s.version = Aviary::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ['Tate Johnson']
9
+ s.email = ['tate@tatey.com']
10
+ s.homepage = 'https://github.com/tatey/aviary'
11
+ s.summary = %q{A static photo gallery generator for Twitter}
12
+ s.description = %q{Aviary generates a static photo gallery using Twitter hashtags}
13
+
14
+ s.rubyforge_project = s.name
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_development_dependency('bundler', '~> 1.0.10')
22
+ s.add_development_dependency('webmock', '~> 1.6.2')
23
+ s.add_development_dependency('minitest', '~> 2.0.2')
24
+
25
+ s.add_runtime_dependency('base58', '~> 0.1')
26
+ s.add_runtime_dependency('dm-core', '~> 1.0.2')
27
+ s.add_runtime_dependency('dm-sqlite-adapter', '~> 1.0.2')
28
+ s.add_runtime_dependency('dm-migrations', '~> 1.0.2')
29
+ s.add_runtime_dependency('dm-validations', '~> 1.0.2')
30
+ s.add_runtime_dependency('nokogiri', '~> 1.4.4')
31
+ s.add_runtime_dependency('twitter', '~> 1.1.2')
32
+ end
data/bin/aviary ADDED
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ require 'optparse'
6
+ require 'aviary'
7
+
8
+ command = nil
9
+ options = {}
10
+ help = <<-HELP
11
+ Aviary generates a static photo gallery from Twitter hashtags.
12
+
13
+ Usage:
14
+ aviary new HASHTAG # Setup files and directories
15
+ aviary search HASHTAG [options...] # Search tagged tweets with photos
16
+ aviary build [options...] # Build gallery
17
+
18
+ Help:
19
+ aviary <command> --help
20
+
21
+ HELP
22
+
23
+ case ARGV[0]
24
+ when 'new'
25
+ if ARGV.size == 2 && ARGV[1] != "--help"
26
+ options[:source] = File.join(Dir.pwd, ARGV[1])
27
+ options[:hashtag] = ARGV[1]
28
+ command = proc { |config| Aviary::Generator.new(config) }
29
+ else
30
+ puts "Invalid argument. Try `aviary new HASHTAG`"
31
+ exit 1
32
+ end
33
+ when 'search'
34
+ OptionParser.new do |o|
35
+ o.banner = 'Usage: aviary search HASHTAG [options...]'
36
+
37
+ o.on('--source DIR', 'Path to source') do |arg|
38
+ options[:source] = arg
39
+ end
40
+
41
+ o.on('--flickr-api-key KEY', 'Use photos hosted on Flickr') do |arg|
42
+ options[:flickr_api_key] = arg
43
+ end
44
+
45
+ o.on('--limit NUM', Integer, 'Number of pages to search (100 statuses per page)') do |arg|
46
+ options[:limit] = arg
47
+ end
48
+
49
+ o.parse!(ARGV)
50
+ end
51
+
52
+ if ARGV.size == 2
53
+ options[:hashtag] = ARGV[1]
54
+ command = proc { |config| Aviary::Search.new(config) }
55
+ else
56
+ puts "Invalid argument. Run `aviary search --help` for assistance."
57
+ exit 1
58
+ end
59
+ when 'build'
60
+ OptionParser.new do |o|
61
+ o.banner = 'Usage: aviary build [options...]'
62
+
63
+ o.on('--destination DIR', 'Path to generated gallery') do |arg|
64
+ options[:dest] = arg
65
+ end
66
+
67
+ o.on('--source DIR', 'Path to source') do |arg|
68
+ options[:source] = arg
69
+ end
70
+
71
+ o.on('--per-page NUM', Integer, 'Number of photos per page') do |arg|
72
+ options[:per_page] = arg
73
+ end
74
+
75
+ o.parse!(ARGV)
76
+ end
77
+
78
+ command = proc { |config| Aviary::Site.new(config) }
79
+ when '--help'
80
+ puts help
81
+ exit 0
82
+ else
83
+ puts "Invalid command. Run `aviary --help` for assistance."
84
+ exit 1
85
+ end
86
+
87
+ command.call(Aviary::Configuration.new(:default, options)).process
@@ -0,0 +1,95 @@
1
+ html, body {
2
+ margin: 0;
3
+ padding: 0;
4
+ border: 0;
5
+ background: #222222;
6
+ font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
7
+ color: #fff;
8
+ text-align: center;
9
+ text-shadow: -1px -1px 1px #000;
10
+ }
11
+
12
+ body {
13
+ width: 750px;
14
+ margin: 0 auto;
15
+ }
16
+
17
+ h1 {
18
+ margin-bottom: 0;
19
+ font-size: 30pt;
20
+ font-weight: normal;
21
+ }
22
+
23
+ a {
24
+ color: #fff;
25
+ text-decoration: none;
26
+ }
27
+
28
+ p a {
29
+ border-bottom: 1px solid #fff;
30
+ }
31
+
32
+ a.button {
33
+ display: inline-block;
34
+ margin: 20px 5px 50px 5px;
35
+ padding: 10px 20px;
36
+ background: #333;
37
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#444), to(#333));
38
+ background: -moz-linear-gradient(0% 100% 90deg, #333, #444);
39
+ -webkit-border-radius: 5px;
40
+ -moz-border-radius: 5px;
41
+ -webkit-box-shadow: inset 0 1px 0 0 #555;
42
+ -moz-box-shadow: inset 0 1px 0 0 #555;
43
+ border: 1px solid #111;
44
+ font-size: 18pt;
45
+ text-decoration: none;
46
+ color: #fff;
47
+ }
48
+
49
+ a.button:active, a.button:hover {
50
+ background: #444;
51
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#555), to(#444));
52
+ background: -moz-linear-gradient(0% 100% 90deg, #444, #555);
53
+ }
54
+
55
+ ul {
56
+ margin: 0;
57
+ padding: 0;
58
+ list-style-type: none;
59
+ }
60
+
61
+ ul li {
62
+ padding: 35px 0;
63
+ }
64
+
65
+ ul li img.photo {
66
+ border: none;
67
+ -webkit-box-shadow: 0 0 25px #111;
68
+ -moz-box-shadow: 0 0 25px #111;
69
+ -webkit-transform: scale(1);
70
+ -webkit-transition-timing-function: ease-out;
71
+ -webkit-transition-duration: 100ms;
72
+ -moz-transform: scale(1);
73
+ -moz-transition-timing-function: ease-out;
74
+ -moz-transition-duration: 100ms;
75
+ }
76
+
77
+ ul li img.photo:hover {
78
+ -webkit-transform: scale(1.05);
79
+ -webkit-transition-timing-function: ease-out;
80
+ -webkit-transition-duration: 100ms;
81
+ -moz-transform: scale(1.05);
82
+ -moz-transition-timing-function: ease-out;
83
+ -moz-transition-duration: 100ms;
84
+ }
85
+
86
+ blockquote p {
87
+ width: 500px;
88
+ margin: 0 auto;
89
+ color: #aaa;
90
+ }
91
+
92
+ p#author {
93
+ font-size: 10pt;
94
+ color: #aaa;
95
+ }
@@ -0,0 +1,38 @@
1
+ (function($) {
2
+ $(document).ready(function() {
3
+ // Remove photos that failed to load after 20 seconds.
4
+ window.setTimeout(function() {
5
+ $('img.photo:hidden')
6
+ .closest('li')
7
+ .fadeOut(function() {
8
+ $(this)
9
+ .remove();
10
+ });
11
+ }, 20000);
12
+
13
+ $('li').each(function(i, el) {
14
+ var $el = $(el);
15
+ // Hide contents of each list element.
16
+ $el
17
+ .children()
18
+ .hide();
19
+ // Prepend the loader.
20
+ $el
21
+ .prepend($('<img>', {src: '/loader.gif', className: 'loader'}));
22
+ // When the photo loads, remove the loader and show the photo.
23
+ $el
24
+ .find('img.photo')
25
+ .load(function() {
26
+ $el
27
+ .children('img.loader')
28
+ .fadeOut(function() {
29
+ $(this)
30
+ .remove();
31
+ $el
32
+ .children()
33
+ .fadeIn();
34
+ });
35
+ });
36
+ });
37
+ });
38
+ })(jQuery);
Binary file
@@ -0,0 +1,45 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta name="generator" content="Aviary <%= Aviary::VERSION %> - https://github.com/tatey/aviary">
5
+ <meta charset="utf-8">
6
+ <title>#{{hashtag}}</title>
7
+ <link type="text/css" rel="stylesheet" href="/aviary.css">
8
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
9
+ <script type="text/javascript" src="/aviary.js"></script>
10
+ </head>
11
+ <body>
12
+ <h1><a href="/">#{{hashtag}}</a></h1>
13
+ <p>
14
+ A raw collection of photos tweeted with <a href="http://twitter.com/search/%23{{hashtag}}">#{{hashtag}}</a>
15
+ </p>
16
+ <ul>
17
+ <% image_hosts.each do |image_host| %>
18
+ <li>
19
+ <a href="<%= image_host.href %>">
20
+ <img class="photo" src="<%= image_host.src %>">
21
+ </a>
22
+ <blockquote>
23
+ <p>
24
+ <%= h image_host.status.text %>
25
+ <cite>
26
+ <a href="http://twitter.com/<%= image_host.status.from_user %>/status/<%= image_host.status.id %>">
27
+ @<%= image_host.status.from_user %>
28
+ </a>
29
+ </cite>
30
+ </p>
31
+ </blockquote>
32
+ </li>
33
+ <% end %>
34
+ </ul>
35
+ <% if paginator.prev_page? %>
36
+ <a class="button" id="prev" href="/page<%= paginator.prev_page %>/" title="Previous">&#9668;</a>
37
+ <% end %>
38
+ <% if paginator.next_page? %>
39
+ <a class="button" id="next" href="/page<%= paginator.next_page %>/" title="Next">&#9658;</a>
40
+ <% end %>
41
+ <p id="author">
42
+ Generated by <a href="https://github.com/tatey/aviary">Aviary</a>
43
+ </p>
44
+ </body>
45
+ </html>