gallerist 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/CONTRIBUTING.md +53 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE +25 -0
  6. data/README.md +57 -0
  7. data/Rakefile +16 -0
  8. data/assets/stylesheets/main.scss +17 -0
  9. data/bin/gallerist +59 -0
  10. data/config.ru +21 -0
  11. data/gallerist.gemspec +32 -0
  12. data/lib/gallerist.rb +46 -0
  13. data/lib/gallerist/app.rb +230 -0
  14. data/lib/gallerist/errors.rb +12 -0
  15. data/lib/gallerist/helpers.rb +72 -0
  16. data/lib/gallerist/library.rb +100 -0
  17. data/lib/gallerist/middleware/raise_warmup_exceptions.rb +24 -0
  18. data/lib/gallerist/middleware/show_exceptions.rb +40 -0
  19. data/lib/gallerist/models/admin_data.rb +10 -0
  20. data/lib/gallerist/models/album.rb +30 -0
  21. data/lib/gallerist/models/album_photo.rb +20 -0
  22. data/lib/gallerist/models/base_model.rb +32 -0
  23. data/lib/gallerist/models/image_proxies_model.rb +11 -0
  24. data/lib/gallerist/models/image_proxy_state.rb +22 -0
  25. data/lib/gallerist/models/master.rb +25 -0
  26. data/lib/gallerist/models/model_resource.rb +22 -0
  27. data/lib/gallerist/models/person.rb +46 -0
  28. data/lib/gallerist/models/person_model.rb +10 -0
  29. data/lib/gallerist/models/person_photo.rb +39 -0
  30. data/lib/gallerist/models/photo.rb +100 -0
  31. data/lib/gallerist/models/tag.rb +31 -0
  32. data/lib/gallerist/models/tag_photo.rb +20 -0
  33. data/lib/rack/handler/unicorn.rb +34 -0
  34. data/views/500.erb +5 -0
  35. data/views/album.erb +9 -0
  36. data/views/index.erb +24 -0
  37. data/views/layout.erb +34 -0
  38. data/views/partials/thumbnail.erb +13 -0
  39. data/views/person.erb +9 -0
  40. data/views/photos.erb +9 -0
  41. data/views/tag.erb +9 -0
  42. metadata +183 -0
@@ -0,0 +1,10 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2015, Sebastian Staudt
5
+
6
+ class Gallerist::PersonModel < Gallerist::BaseModel
7
+
8
+ self.abstract_class = true
9
+
10
+ end
@@ -0,0 +1,39 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2015, Sebastian Staudt
5
+
6
+ class Gallerist::PersonPhoto < Gallerist::PersonModel
7
+
8
+ iphoto do
9
+ self.table_name = 'RKDetectedFace'
10
+
11
+ has_one :person, primary_key: 'faceKey', foreign_key: 'faceKey'
12
+
13
+ alias_attribute :master_uuid, :masterUuid
14
+ alias_attribute :person_id, :faceKey
15
+
16
+ def photo
17
+ Gallerist::Photo.find_by master_uuid: master_uuid
18
+ end
19
+
20
+ def photo_id
21
+ photo.id
22
+ end
23
+ end
24
+
25
+ photos do
26
+ self.table_name = 'RKPersonVersion'
27
+
28
+ has_one :person, primary_key: 'personId', foreign_key: 'modelId'
29
+ has_one :photo, primary_key: 'versionId', foreign_key: 'modelId'
30
+
31
+ alias_attribute :person_id, :personId
32
+ alias_attribute :photo_id, :versionId
33
+ end
34
+
35
+ def inspect
36
+ '#<%s person_id=%d photo_id=%s>' % [ self.class, person_id, photo_id ]
37
+ end
38
+
39
+ end
@@ -0,0 +1,100 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2015, Sebastian Staudt
5
+
6
+ class Gallerist::Photo < Gallerist::BaseModel
7
+
8
+ self.table_name = 'RKVersion'
9
+
10
+ has_one :image_proxy_state, foreign_key: 'versionId'
11
+ has_one :master, primary_key: 'masterId', foreign_key: 'modelId'
12
+ has_one :model_resource, -> { where model_type: 2 }, foreign_key: 'attachedModelId'
13
+ has_many :album_photos, primary_key: 'modelId', foreign_key: 'versionId'
14
+ has_many :albums, through: :album_photos
15
+ has_many :tag_photos, primary_key: 'modelId', foreign_key: 'versionId'
16
+ has_many :tags, -> { distinct }, through: :tag_photos
17
+
18
+ iphoto do
19
+ alias_attribute :master_uuid, :masterUuid
20
+
21
+ def person_photos
22
+ Gallerist::PersonPhoto.where master_uuid: master.uuid
23
+ end
24
+ end
25
+
26
+ photos do
27
+ has_many :person_photos, primary_key: 'modelId', foreign_key: 'versionId'
28
+ end
29
+
30
+ alias_attribute :date, :imageDate
31
+ alias_attribute :file_name, :fileName
32
+ alias_attribute :is_favorite, :isFavorite
33
+ alias_attribute :show_in_library, :showInLibrary
34
+
35
+ delegate :thumbnail_available?, to: :image_proxy_state, allow_nil: true
36
+
37
+ scope :favorites, -> { where(is_favorite: true) }
38
+
39
+ photos do
40
+ default_scope do
41
+ select(:masterId, :modelId, :fileName, :imageDate, :type, :uuid).
42
+ where(show_in_library: true)
43
+ end
44
+ end
45
+
46
+ iphoto do
47
+ default_scope do
48
+ select(:masterId, :modelId, :fileName, :imageDate, :uuid).
49
+ where(show_in_library: true)
50
+ end
51
+ end
52
+
53
+ def image_path
54
+ if model_resource && !video?
55
+ uuid = model_resource.uuid
56
+ first, second = uuid[0].ord.to_s, uuid[1].ord.to_s
57
+
58
+ File.join 'resources', 'modelresources', first, second, uuid, model_resource.file_name
59
+ else
60
+ File.join 'Masters', master.path
61
+ end
62
+ end
63
+
64
+ def inspect
65
+ "#<%s id=%d uuid=%s file_name='%s'>" % [ self.class, id, uuid, file_name ]
66
+ end
67
+
68
+ def path
69
+ File.dirname master.path
70
+ end
71
+
72
+ # ActiveRecord does not support has_many-through associations across
73
+ # different databases, so we have to query the persons manually
74
+ photos do
75
+ def persons
76
+ Gallerist::Person.where modelId: person_photos.map(&:person_id)
77
+ end
78
+ end
79
+
80
+ iphoto do
81
+ def persons
82
+ Gallerist::Person.where faceKey: person_photos.map(&:person_id)
83
+ end
84
+ end
85
+
86
+ def preview_path
87
+ dir_name = File.dirname master.path
88
+ image_name = File.basename(master.path, '.*') + '.jpg'
89
+ File.join 'Previews', dir_name, image_name
90
+ end
91
+
92
+ def small_thumbnail_path
93
+ File.join 'Thumbnails', image_proxy_state.small_thumbnail_path
94
+ end
95
+
96
+ def video?
97
+ type == 8
98
+ end
99
+
100
+ end
@@ -0,0 +1,31 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2015, Sebastian Staudt
5
+
6
+ class Gallerist::Tag < Gallerist::BaseModel
7
+
8
+ self.table_name = 'RKKeyword'
9
+
10
+ has_many :tag_photos, primary_key: 'modelId', foreign_key: 'keywordId'
11
+ has_many :photos, -> { distinct }, through: :tag_photos
12
+
13
+ alias_attribute :simple_name, :searchName
14
+
15
+ default_scope { select(:modelId, :name, :searchName) }
16
+ scope :nonempty, -> {
17
+ joins(:tag_photos).
18
+ select('count(RKKeywordForVersion.keywordId) as photos_count').
19
+ group('RKKeywordForVersion.keywordId').
20
+ having('photos_count > 0')
21
+ }
22
+
23
+ def inspect
24
+ "#<%s id=%d name='%s'>" % [ self.class, id, name ]
25
+ end
26
+
27
+ def to_s
28
+ name
29
+ end
30
+
31
+ end
@@ -0,0 +1,20 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2015, Sebastian Staudt
5
+
6
+ class Gallerist::TagPhoto < Gallerist::BaseModel
7
+
8
+ self.table_name = 'RKKeywordForVersion'
9
+
10
+ has_one :tag, primary_key: 'keywordId', foreign_key: 'modelId'
11
+ has_one :photo, primary_key: 'versionId', foreign_key: 'modelId'
12
+
13
+ alias_attribute :tag_id, :keywordId
14
+ alias_attribute :photo_id, :versionId
15
+
16
+ def inspect
17
+ '#<%s tag_id=%d photo_id=%d>' % [ self.class, tag_id, photo_id ]
18
+ end
19
+
20
+ end
@@ -0,0 +1,34 @@
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2015, Sebastian Staudt
5
+
6
+ require 'unicorn'
7
+
8
+ module Rack::Handler::Unicorn
9
+
10
+ class << self
11
+
12
+ def run(app, options = {})
13
+ environment = ENV['RACK_ENV'] || 'development'
14
+ default_host = (environment == 'development') ? 'localhost' : '0.0.0.0'
15
+ options[:Host] ||= default_host
16
+
17
+ unicorn_options = {
18
+ listeners: [ '%s:%d' % [ options[:Host], options[:Port] ] ],
19
+ worker_processes: options[:worker_processes] || 1
20
+ }
21
+
22
+ ::Unicorn::Launcher.daemonize!(unicorn_options) if options[:daemonize]
23
+ ::Unicorn::HttpServer.new(app, unicorn_options).start.join
24
+ end
25
+
26
+ def environment
27
+ ENV['RACK_ENV']
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ Rack::Handler.register :unicorn, Rack::Handler::Unicorn
@@ -0,0 +1,5 @@
1
+ <div class="jumbotron">
2
+ <h2><span class="text-danger">Internal Server Error</span></h2>
3
+
4
+ Something went wrong while processing this request.
5
+ </div>
@@ -0,0 +1,9 @@
1
+ <h1><%= @album.name %></h1>
2
+
3
+ <div class="row">
4
+ <% @album.photos.order(:date).each do |photo| %>
5
+ <div class="col-md-3">
6
+ <%= partial :thumbnail, locals: { photo: photo } %>
7
+ </div>
8
+ <% end %>
9
+ </div>
@@ -0,0 +1,24 @@
1
+ <div class="list-group">
2
+ <a class="list-group-item" href="/photos">All photos</a>
3
+ <a class="list-group-item" href="/favorites">Favorites</a>
4
+ </div>
5
+
6
+ <h2>Albums</h2>
7
+
8
+ <div class="list-group">
9
+ <% @albums.each do |album| %>
10
+ <%= link_to album, 'list-group-item' %>
11
+ <% end %>
12
+ </div>
13
+
14
+ <h2>Tags</h2>
15
+
16
+ <h3>
17
+ <%= @tags.map { |tag| link_to tag }.join %>
18
+ </h3>
19
+
20
+ <h2>Persons</h2>
21
+
22
+ <h3>
23
+ <%= @persons.map { |person| link_to person }.join %>
24
+ </h3>
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title><%= title %></title>
5
+
6
+ <link href="<%= stylesheet_path 'main' %>" rel="stylesheet">
7
+
8
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
9
+ </head>
10
+ <body>
11
+ <nav class="navbar navbar-default navbar-inverse navbar-static-top">
12
+ <div class="container-fluid">
13
+ <div class="navbar-header">
14
+ <span class="navbar-brand"><strong>Gallerist</strong></span>
15
+ </div>
16
+ <ul class="nav navbar-nav">
17
+ <% (navbar || []).each_with_index do |item, idx| %>
18
+ <li<%= ' class="active"' if idx == navbar.size - 1 %>>
19
+ <% if route_exists item.first %>
20
+ <a href="<%= item.first %>" ><%= item.last %></a>
21
+ <% else %>
22
+ <span class="navbar-text"><%= item.last %></span>
23
+ <% end %>
24
+ </li>
25
+ <% end %>
26
+ </ul>
27
+ </div>
28
+ </nav>
29
+
30
+ <div class="container-fluid">
31
+ <%= yield %>
32
+ </div>
33
+ </body>
34
+ </html>
@@ -0,0 +1,13 @@
1
+ <div class="thumbnail">
2
+ <a href="<%= url_for(photo) %>">
3
+ <img src="/thumbs/<%= photo.id %>">
4
+ </a>
5
+ <div class="caption">
6
+ <% unless photo.tags.to_a.empty? %>
7
+ <p>Tags: <%= photo.tags.map { |t| link_to t }.join('') %></p>
8
+ <% end %>
9
+ <% unless photo.persons.to_a.empty? %>
10
+ <p>Persons: <%= photo.persons.map { |t| link_to t }.join('') %></p>
11
+ <% end %>
12
+ </div>
13
+ </div>
@@ -0,0 +1,9 @@
1
+ <h1><%= @person.name %></h1>
2
+
3
+ <div class="row">
4
+ <% @person.photos.order(:date).each do |photo| %>
5
+ <div class="col-md-3">
6
+ <%= partial :thumbnail, locals: { photo: photo } %>
7
+ </div>
8
+ <% end %>
9
+ </div>
@@ -0,0 +1,9 @@
1
+ <h1><%= @title %></h1>
2
+
3
+ <div class="row">
4
+ <% @photos.order(:date).each do |photo| %>
5
+ <div class="col-md-3">
6
+ <%= partial :thumbnail, locals: { photo: photo } %>
7
+ </div>
8
+ <% end %>
9
+ </div>
@@ -0,0 +1,9 @@
1
+ <h1><%= @tag.name %></h1>
2
+
3
+ <div class="row">
4
+ <% @tag.photos.order(:date).each do |photo| %>
5
+ <div class="col-md-3">
6
+ <%= partial :thumbnail, locals: { photo: photo } %>
7
+ </div>
8
+ <% end %>
9
+ </div>
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gallerist
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Staudt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bootstrap-sass
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '3.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sinatra
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.4'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sprockets-helpers
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: unicorn
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '4.8'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '4.8'
111
+ description: View Photos and iPhoto libraries in your browser
112
+ email:
113
+ - koraktor@gmail.com
114
+ executables:
115
+ - gallerist
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - .gitignore
120
+ - CONTRIBUTING.md
121
+ - Gemfile
122
+ - LICENSE
123
+ - README.md
124
+ - Rakefile
125
+ - assets/stylesheets/main.scss
126
+ - bin/gallerist
127
+ - config.ru
128
+ - gallerist.gemspec
129
+ - lib/gallerist.rb
130
+ - lib/gallerist/app.rb
131
+ - lib/gallerist/errors.rb
132
+ - lib/gallerist/helpers.rb
133
+ - lib/gallerist/library.rb
134
+ - lib/gallerist/middleware/raise_warmup_exceptions.rb
135
+ - lib/gallerist/middleware/show_exceptions.rb
136
+ - lib/gallerist/models/admin_data.rb
137
+ - lib/gallerist/models/album.rb
138
+ - lib/gallerist/models/album_photo.rb
139
+ - lib/gallerist/models/base_model.rb
140
+ - lib/gallerist/models/image_proxies_model.rb
141
+ - lib/gallerist/models/image_proxy_state.rb
142
+ - lib/gallerist/models/master.rb
143
+ - lib/gallerist/models/model_resource.rb
144
+ - lib/gallerist/models/person.rb
145
+ - lib/gallerist/models/person_model.rb
146
+ - lib/gallerist/models/person_photo.rb
147
+ - lib/gallerist/models/photo.rb
148
+ - lib/gallerist/models/tag.rb
149
+ - lib/gallerist/models/tag_photo.rb
150
+ - lib/rack/handler/unicorn.rb
151
+ - views/500.erb
152
+ - views/album.erb
153
+ - views/index.erb
154
+ - views/layout.erb
155
+ - views/partials/thumbnail.erb
156
+ - views/person.erb
157
+ - views/photos.erb
158
+ - views/tag.erb
159
+ homepage: https://github.com/koraktor/gallerist
160
+ licenses:
161
+ - BSD
162
+ metadata: {}
163
+ post_install_message:
164
+ rdoc_options: []
165
+ require_paths:
166
+ - lib
167
+ required_ruby_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - '>='
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ required_rubygems_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - '>='
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ requirements: []
178
+ rubyforge_project:
179
+ rubygems_version: 2.4.6
180
+ signing_key:
181
+ specification_version: 4
182
+ summary: A web application to browse Apple Photos and iPhoto libraries
183
+ test_files: []