lentil 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +15 -1
- data/app/assets/javascripts/lentil/addfancybox.js +17 -1
- data/app/assets/javascripts/lentil/addinfinitescroll.js.erb +1 -2
- data/app/assets/javascripts/lentil/imageerrors.js +4 -4
- data/app/models/lentil/image.rb +8 -4
- data/app/views/admin/lentil_images/_moderation_form_body.html.erb +7 -1
- data/app/views/lentil/images/_image_tiles.erb +6 -2
- data/app/views/lentil/images/animate.html.erb +9 -1
- data/app/views/lentil/images/index.html.erb +19 -0
- data/app/views/lentil/images/show.html.erb +7 -1
- data/app/views/lentil/thisorthat/_battle_form.html.erb +12 -2
- data/db/migrate/20141106172834_add_type_to_images.rb +6 -0
- data/lib/lentil/admin/images.rb +12 -3
- data/lib/lentil/instagram_harvester.rb +30 -2
- data/lib/lentil/version.rb +1 -1
- data/lib/tasks/image_services.rake +88 -1
- data/test/dummy/db/schema.rb +3 -1
- data/test/fixtures/lentil/images.yml +73 -0
- data/test/integration/lentil/images_show_test.rb +7 -5
- data/test/test_helper.rb +1 -1
- data/vendor/assets/javascripts/animatedimages/js/jquery.gridrotator.js +33 -20
- metadata +10 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 942c1dd9c7d9d2eeffd3950d921c979fc969399a
|
4
|
+
data.tar.gz: 10b00660f681388bd87560f94bb4f594c643d072
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7536b168f00124322e37b23d9d6f93cbc048a3da9ae04375d639b3d3f27ad05ee254a2a398a653b48e24ca28a602b1353693407b1bef300aa30c0f392583076
|
7
|
+
data.tar.gz: 9ca11239e8fa46c2c0c96803b49578df3d01358da04d0b101fc9d48b786d4e9026b18ee047277194f093e2c588dc35cbb0c6dc812f0874a3954f864c9b84fb29
|
data/README.md
CHANGED
@@ -72,6 +72,19 @@ You ought to see a message like: "15 new images added"
|
|
72
72
|
- Go to <http://localhost:3000/admin/lentil_images> and click on "Moderate New." Approve or reject some images. Once you've approved some, go to <http://localhost:3000> to see your approved images.
|
73
73
|
- Congratulations! You're now up and running!
|
74
74
|
|
75
|
+
## Harvest Videos
|
76
|
+
Video harvesting is builtin to the image harvesting feature. Only once a single task has to be run to migrate the existing data to accomodate for schema.
|
77
|
+
After updating lentil to the latest release run
|
78
|
+
```sh
|
79
|
+
bundle exec rails generate lentil:install
|
80
|
+
bundle exec rake lentil:image_services:restore_videos
|
81
|
+
```
|
82
|
+
|
83
|
+
You ought to see a message like: "x record(s) updated"
|
84
|
+
|
85
|
+
Videos can be moderated like images.
|
86
|
+
In the home page and animate views videos will autoplay, muted and looped
|
87
|
+
|
75
88
|
## Scheduling tasks
|
76
89
|
|
77
90
|
There are several rake tasks that you should schedule to run on a recurring basis:
|
@@ -80,9 +93,10 @@ There are several rake tasks that you should schedule to run on a recurring basi
|
|
80
93
|
- `rake lentil:image_services:test_image_files[number_of_images,image_service]` checks that the image content for approved images is still available. After 3 failures, Lentil will stop displaying the images. After 10 failures, Lentil will stop checking. Defaults to checking 10 Instagram images. Images will not be checked more than once per day.
|
81
94
|
- `rake lentil:popularity:update_score` recalculates the popularity score based on "likes" and "battles."
|
82
95
|
|
83
|
-
Additionally, there are
|
96
|
+
Additionally, there are three optional rake tasks that support image file harvesting for longer-term retention:
|
84
97
|
|
85
98
|
- `rake lentil:image_services:save_image_files[number_of_images,image_service,base_directory]` Lentil normally only stores image metadata, but this task will save the image file to a specified directory. This file will still not be used by Lentil, but the file retrieval will be noted in the Image model. Defaults to 50 Instagram images, saving to the path specified by the `base_image_file_dir` option from `config/lentil_config.yml`.
|
99
|
+
- `rake lentil:image_services:dump_metadata[image_service,base_directory]` Extracts all image metadata from the database and writes them as json files. Defaults to saving to the path specified by the `base_image_file_dir` option from `config/lentil_config.yml`.
|
86
100
|
- `rake lentil:image_services:submit_donor_agreements[number_of_images,image_service]` will submit a donor agreement (using the `donor_agreement_text` option from `config/lentil_config.yml`) as a comment on approved Instagram images that have been in the system for at least a week. Currently defaults to one image.
|
87
101
|
|
88
102
|
> In order to submit comments, you will need to generate an access token for the user that will submit the comments. See the [Instagram documentation](http://instagram.com/developer/authentication/) and a [discussion of access token expiration](https://groups.google.com/forum/?fromgroups=#!searchin/instagram-api-developers/access$20token%7Csort:date/instagram-api-developers/OBOTwIh3FSw/9hTccUX1Jq4J).
|
@@ -76,9 +76,10 @@ function addfancybox() {
|
|
76
76
|
closeEffect : 'none',
|
77
77
|
nextEffect : 'none',
|
78
78
|
prevEffect : 'none',
|
79
|
+
live : true,
|
79
80
|
loop : false,
|
80
81
|
minWidth : '250px',
|
81
|
-
type: '
|
82
|
+
type: 'html',
|
82
83
|
helpers : {
|
83
84
|
title : { type : 'inside' },
|
84
85
|
overlay : { locked : false }
|
@@ -90,6 +91,21 @@ function addfancybox() {
|
|
90
91
|
window.history.pushState(null,null,FancyBoxCloseFunctionState.pathname);
|
91
92
|
},
|
92
93
|
beforeShow : function() {
|
94
|
+
var img = $(this.element).children(".instagram-img");
|
95
|
+
if($(img).attr("data-media-type") === "video") {
|
96
|
+
var video_url = $(img).attr("src");
|
97
|
+
//this.content = "<video src='" + video_url + "' height='320' width='320' controls='controls'></video>";
|
98
|
+
$(".fancybox-inner").html('<video controls="controls" height="100%" width="90%" src="' + video_url + '"></video>');
|
99
|
+
var vid = $(".fancybox-inner").children("video")[0];
|
100
|
+
vid.oncanplay = function() {
|
101
|
+
$.fancybox.reposition();
|
102
|
+
}
|
103
|
+
}
|
104
|
+
else {
|
105
|
+
var image_url = $(img).attr("src");
|
106
|
+
$(".fancybox-inner").html('<img class="fancybox-image" src="' + image_url + '" />');
|
107
|
+
}
|
108
|
+
|
93
109
|
this.title = $(this.element).next(".text-overlay").html();
|
94
110
|
imageId = $(this.element).parents("div").attr("id");
|
95
111
|
$(".fancybox-wrap").attr('id', imageId);
|
@@ -33,7 +33,6 @@ function addinfinitescroll() {
|
|
33
33
|
}
|
34
34
|
},
|
35
35
|
function () {
|
36
|
-
addfancybox();
|
37
36
|
addimageerrors();
|
38
37
|
// on callback, if fancybox is open
|
39
38
|
// then close it and reopen at the same spot
|
@@ -47,4 +46,4 @@ function addinfinitescroll() {
|
|
47
46
|
}
|
48
47
|
});
|
49
48
|
}
|
50
|
-
}
|
49
|
+
}
|
@@ -1,8 +1,8 @@
|
|
1
1
|
function addimageerrors() {
|
2
|
-
$("
|
2
|
+
$(".instagram-img, .battle-img, .fancybox-img").off("error").on("error", function () {
|
3
3
|
$(this).parents("div.image-tile, li.image-animate-tile").remove();
|
4
|
-
if ($("body.images_animate") || $("body.images_staff_picks_animate")) {
|
4
|
+
/*if ($("body.images_animate") || $("body.images_staff_picks_animate")) {
|
5
5
|
addanimatedimages();
|
6
|
-
}
|
6
|
+
}*/
|
7
7
|
});
|
8
|
-
}
|
8
|
+
}
|
data/app/models/lentil/image.rb
CHANGED
@@ -35,8 +35,10 @@
|
|
35
35
|
class Lentil::Image < ActiveRecord::Base
|
36
36
|
attr_accessible :description, :title, :user_id, :state, :staff_like, :url, :long_url, :external_identifier,
|
37
37
|
:original_datetime, :popular_score, :taggings, :tag_id, :moderator, :moderated_at, :second_moderation,
|
38
|
-
:do_not_request_donation, :donor_agreement_rejected
|
39
|
-
|
38
|
+
:do_not_request_donation, :donor_agreement_rejected, :media_type, :video_url
|
39
|
+
|
40
|
+
attr_protected :original_metadata
|
41
|
+
|
40
42
|
has_many :won_battles, :class_name => "Battle"
|
41
43
|
has_many :losers, :through => :battles
|
42
44
|
has_many :lost_battles, :class_name => "Battle", :foreign_key => "loser_id"
|
@@ -54,8 +56,6 @@ class Lentil::Image < ActiveRecord::Base
|
|
54
56
|
has_many :licensings
|
55
57
|
has_many :licenses, :through=>:licensings
|
56
58
|
|
57
|
-
serialize :original_metadata, Hash
|
58
|
-
|
59
59
|
belongs_to :moderator, :class_name => Lentil::AdminUser
|
60
60
|
|
61
61
|
default_scope where("failed_file_checks < 3")
|
@@ -199,4 +199,8 @@ class Lentil::Image < ActiveRecord::Base
|
|
199
199
|
end
|
200
200
|
|
201
201
|
end
|
202
|
+
|
203
|
+
def original_metadata=(meta)
|
204
|
+
write_attribute(:original_metadata, meta.to_hash)
|
205
|
+
end
|
202
206
|
end
|
@@ -18,7 +18,13 @@
|
|
18
18
|
<% @images.each do |image| %>
|
19
19
|
<tr class="moderation">
|
20
20
|
<%= semantic_fields_for "image[#{image.id}]", image do |f| %>
|
21
|
-
<td
|
21
|
+
<td>
|
22
|
+
<% unless image.media_type == "video" %>
|
23
|
+
<%= link_to_large_admin_image(image) %>
|
24
|
+
<% else %>
|
25
|
+
<%= link_to(video_tag(image.video_url, controls: true, size: "250x250"), admin_lentil_image_path(image)) %>
|
26
|
+
<% end %>
|
27
|
+
</td>
|
22
28
|
<td><%= image.description %></td>
|
23
29
|
<td><%= image.user.user_name %></td>
|
24
30
|
<td><%= image.service_tags.map{|tag| tag.name}.join(' | ') %>
|
@@ -1,8 +1,12 @@
|
|
1
1
|
<div class="images">
|
2
2
|
<% @images.each do |image| %>
|
3
3
|
<div id="image_<%= image.id %>" class="grid__cell image-tile">
|
4
|
-
<%= link_to url_for(image), 'data-fancybox-href' => image.
|
5
|
-
|
4
|
+
<%= link_to url_for(image), 'data-fancybox-href' => image.video_url, 'data-fancybox-group' => "image-tile-gallery", :class => :fancybox do %>
|
5
|
+
<% unless image.media_type == "video" %>
|
6
|
+
<%= image_tag(image.jpeg, :class => "instagram-img " + image.id.to_s, :alt => image.description, :data => {:battles_count => image.battles_count, :win_pct => image.win_pct, :popularity => image.popular_score, :staff_like => image.staff_like, :like_votes_count => image.like_votes_count, :media_type => image.media_type}) %>
|
7
|
+
<% else %>
|
8
|
+
<%= video_tag(image.video_url, :autoplay => "true", :muted => "true", :loop => "true", :class => "instagram-img " + image.id.to_s, :height => "100%", :width => "100%", :poster => image.jpeg, :data => {:battles_count => image.battles_count, :win_pct => image.win_pct, :popularity => image.popular_score, :staff_like => image.staff_like, :like_votes_count => image.like_votes_count, :media_type => image.media_type}) %>
|
9
|
+
<% end %>
|
6
10
|
<% end %>
|
7
11
|
|
8
12
|
<%= render "/layouts/lentil/image_popup", :image => image %>
|
@@ -7,7 +7,15 @@
|
|
7
7
|
<div id="ri-grid" class="ri-grid ri-grid-size-2 grid__cell animated-images staff-picks-animated" style="padding:0; margin:0;">
|
8
8
|
<ul>
|
9
9
|
<% @images.each do |image| %>
|
10
|
-
<li class="image-animate-tile"
|
10
|
+
<li class="image-animate-tile">
|
11
|
+
<a href="#">
|
12
|
+
<% unless image.media_type == "video" %>
|
13
|
+
<%= image_tag(image.jpeg, :class => "instagram-img") %>
|
14
|
+
<% else %>
|
15
|
+
<%= video_tag(image.video_url, :autoplay => "true", :muted => "true", :loop => "true", :poster => image.jpeg, :class => "instagram-img " + image.id.to_s, :height => "100%", :width => "100%", :data => {:media_type => image.media_type}) %>
|
16
|
+
<% end %>
|
17
|
+
</a>
|
18
|
+
</li>
|
11
19
|
<% end -%>
|
12
20
|
</ul>
|
13
21
|
</div>
|
@@ -5,6 +5,25 @@
|
|
5
5
|
<% end -%>
|
6
6
|
<% title @title %>
|
7
7
|
<%= render :partial => "/layouts/lentil/top_navigation" %>
|
8
|
+
<style>
|
9
|
+
.fancybox-prev {
|
10
|
+
width : 5%;
|
11
|
+
}
|
12
|
+
.fancybox-prev > span {
|
13
|
+
left : 0;
|
14
|
+
visibility: visible;
|
15
|
+
}
|
16
|
+
.fancybox-next {
|
17
|
+
width : 5%;
|
18
|
+
}
|
19
|
+
.fancybox-next > span {
|
20
|
+
right : 0;
|
21
|
+
visibility: visible;
|
22
|
+
}
|
23
|
+
.fancybox-inner {
|
24
|
+
text-align: center;
|
25
|
+
}
|
26
|
+
</style>
|
8
27
|
<section class="wrapper">
|
9
28
|
<div class="grid">
|
10
29
|
<div class="grid__cell header">
|
@@ -17,7 +17,13 @@
|
|
17
17
|
<div class="wrapper">
|
18
18
|
<div class="grid__cell side-filler"></div>
|
19
19
|
<div id="image_<%= @image.id %>" class="image-show grid__cell solo-image">
|
20
|
-
|
20
|
+
<a href="<%= @image.url %>">
|
21
|
+
<% unless @image.media_type == "video" %>
|
22
|
+
<%= image_tag(@image.jpeg, :class => "instagram-img") %>
|
23
|
+
<% else %>
|
24
|
+
<video src="<%= @image.video_url %>" poster="<%= @image.jpeg %>" controls='controls' class="instagram-img <%= @image.id.to_s %>" height="100%" width="100%" data-media-type="<%= @image.media_type %>" ></video>
|
25
|
+
<% end %>
|
26
|
+
</a>
|
21
27
|
<%= render "/layouts/lentil/image_popup", :image => @image %>
|
22
28
|
</div>
|
23
29
|
<div class="grid__cell side-filler"></div>
|
@@ -4,7 +4,12 @@
|
|
4
4
|
<div class="battle-image-wrap grid__cell">
|
5
5
|
<%= semantic_fields_for "image[#{image.id}]", image do |f| %>
|
6
6
|
<div id="image_<%= image.id %>" class="battle-image-tile">
|
7
|
-
<a href="<%= url_for(image) %>" data-fancybox-href= "<%= image.jpeg %>" class="fancybox"
|
7
|
+
<a href="<%= url_for(image) %>" data-fancybox-href= "<%= image.jpeg %>" class="fancybox">
|
8
|
+
<% unless image.media_type == "video" %>
|
9
|
+
<%= image_tag(image.jpeg, :class => "battle-img instagram-img", :data => {:battles_count => image.battles_count, :win_pct => image.win_pct, :popularity => image.popular_score, :staff_like => image.staff_like, :like_votes_count => image.like_votes_count, :media_type => image.media_type}) %>
|
10
|
+
<% else %>
|
11
|
+
<%= video_tag(image.video_url, :class => "instagram-img " + image.id.to_s, :height => "100%", :width => "100%", :poster => image.jpeg, :controls => "controls", :data => {:battles_count => image.battles_count, :win_pct => image.win_pct, :popularity => image.popular_score, :staff_like => image.staff_like, :like_votes_count => image.like_votes_count, :media_type => image.media_type}) %>
|
12
|
+
<% end %>
|
8
13
|
<div class="battle-image-desc trunc-small"><div class="battle-image-inner-desc"><%= truncate(image.description, :length => 35) %></div></div>
|
9
14
|
<div class="battle-image-desc trunc-medium"><div class="battle-image-inner-desc"><%= truncate(image.description, :length => 50) %></div></div>
|
10
15
|
<div class="battle-image-desc trunc-large"><div class="battle-image-inner-desc"><%= truncate(image.description, :length => 70) %></div></div>
|
@@ -23,7 +28,12 @@
|
|
23
28
|
<% @prev_images.each do |image| %>
|
24
29
|
<div class="battle-image-wrap grid__cell" style="background:#e6e6e6">
|
25
30
|
<div id="image_<%= image.id %>" class="battle-image-tile">
|
26
|
-
<a href="<%= url_for(image) %>" data-fancybox-href= "<%= image.jpeg %>" class="fancybox"
|
31
|
+
<a href="<%= url_for(image) %>" data-fancybox-href= "<%= image.jpeg %>" class="fancybox">
|
32
|
+
<% unless image.media_type == "video" %>
|
33
|
+
<%= image_tag(image.jpeg, :class => "battle-img instagram-img", :data => {:battles_count => image.battles_count, :win_pct => image.win_pct, :popularity => image.popular_score, :staff_like => image.staff_like, :like_votes_count => image.like_votes_count, :media_type => image.media_type}) %>
|
34
|
+
<% else %>
|
35
|
+
<%= video_tag(image.video_url, :class => "instagram-img " + image.id.to_s, :height => "100%", :width => "100%", :poster => image.jpeg, :controls => "controls", :data => {:battles_count => image.battles_count, :win_pct => image.win_pct, :popularity => image.popular_score, :staff_like => image.staff_like, :like_votes_count => image.like_votes_count, :media_type => image.media_type}) %>
|
36
|
+
<% end %>
|
27
37
|
<div class="battle-image-desc trunc-small"><div class="battle-image-inner-desc"><%= truncate(image.description, :length => 35) %></div></div>
|
28
38
|
<div class="battle-image-desc trunc-medium"><div class="battle-image-inner-desc"><%= truncate(image.description, :length => 50) %></div></div>
|
29
39
|
<div class="battle-image-desc trunc-large"><div class="battle-image-inner-desc"><%= truncate(image.description, :length => 70) %></div></div>
|
data/lib/lentil/admin/images.rb
CHANGED
@@ -6,6 +6,7 @@ if defined?(ActiveAdmin)
|
|
6
6
|
config.per_page = 10
|
7
7
|
|
8
8
|
filter :state, :as => :select, :collection => proc { Lentil::Image::States }
|
9
|
+
filter :media_type, :as => :select
|
9
10
|
filter :user_user_name, :as => :string, :label => "Username"
|
10
11
|
filter :user_full_name, :as => :string, :label => "Full Name"
|
11
12
|
filter :staff_like, :as => :select
|
@@ -31,7 +32,11 @@ if defined?(ActiveAdmin)
|
|
31
32
|
|
32
33
|
index do
|
33
34
|
column "Image" do |image|
|
34
|
-
|
35
|
+
unless image.media_type == "video"
|
36
|
+
link_to(image_tag(image.image_url, :class => "moderation_thumbnail"), admin_lentil_image_path(image))
|
37
|
+
else
|
38
|
+
link_to(video_tag(image.video_url, controls: true, size: "250x250"), admin_lentil_image_path(image))
|
39
|
+
end
|
35
40
|
end
|
36
41
|
column :id
|
37
42
|
column :description
|
@@ -91,7 +96,11 @@ if defined?(ActiveAdmin)
|
|
91
96
|
image.state_name
|
92
97
|
end
|
93
98
|
row :image do
|
94
|
-
|
99
|
+
unless image.media_type == "video"
|
100
|
+
link_to(image_tag(image.image_url), admin_lentil_image_path(image))
|
101
|
+
else
|
102
|
+
video_tag(image.video_url, controls: true, size: "640x640")
|
103
|
+
end
|
95
104
|
end
|
96
105
|
end
|
97
106
|
active_admin_comments
|
@@ -211,4 +220,4 @@ if defined?(ActiveAdmin)
|
|
211
220
|
redirect_to :back, notice: "#{image_counter} #{'URL'.pluralize(image_counter)} added (out of #{total_urls})", alert: errors.join('<br>').html_safe
|
212
221
|
end
|
213
222
|
end
|
214
|
-
end
|
223
|
+
end
|
@@ -124,7 +124,9 @@ module Lentil
|
|
124
124
|
tags: instagram_metadata.tags,
|
125
125
|
user: instagram_metadata.user,
|
126
126
|
original_datetime: Time.at(instagram_metadata.created_time.to_i).to_datetime,
|
127
|
-
original_metadata: instagram_metadata
|
127
|
+
original_metadata: instagram_metadata,
|
128
|
+
media_type: instagram_metadata.type,
|
129
|
+
video_url: instagram_metadata.videos && instagram_metadata.videos.standard_resolution.url
|
128
130
|
}
|
129
131
|
end
|
130
132
|
|
@@ -152,7 +154,9 @@ module Lentil
|
|
152
154
|
:description => image_data[:name],
|
153
155
|
:url => image_data[:url],
|
154
156
|
:long_url => image_data[:large_url],
|
155
|
-
:
|
157
|
+
:video_url => image_data[:video_url],
|
158
|
+
:original_datetime => image_data[:original_datetime],
|
159
|
+
:media_type => image_data[:media_type]
|
156
160
|
})
|
157
161
|
|
158
162
|
# This is a temporary fix for a bug in the Hashie to_hash method.
|
@@ -240,6 +244,30 @@ module Lentil
|
|
240
244
|
|
241
245
|
response.body
|
242
246
|
end
|
247
|
+
|
248
|
+
#
|
249
|
+
# Retrieve the binary video data for a given Image object
|
250
|
+
#
|
251
|
+
# @param [Image] image An Image model object from the Instagram service
|
252
|
+
#
|
253
|
+
# @raise [Exception] If there are request problems
|
254
|
+
#
|
255
|
+
# @return [String] Binary video data
|
256
|
+
def harvest_video_data(image)
|
257
|
+
response = Typhoeus.get(image.video_url, followlocation: true)
|
258
|
+
|
259
|
+
if response.success?
|
260
|
+
raise "Invalid content type: " + response.headers['Content-Type'] unless (response.headers['Content-Type'] == 'video/mp4')
|
261
|
+
elsif response.timed_out?
|
262
|
+
raise "Request timed out"
|
263
|
+
elsif response.code == 0
|
264
|
+
raise "Could not get an HTTP response"
|
265
|
+
else
|
266
|
+
raise "HTTP request failed: " + response.code.to_s
|
267
|
+
end
|
268
|
+
|
269
|
+
response.body
|
270
|
+
end
|
243
271
|
|
244
272
|
#
|
245
273
|
# Test if an image is still avaiable
|
data/lib/lentil/version.rb
CHANGED
@@ -55,15 +55,24 @@ namespace :lentil do
|
|
55
55
|
|
56
56
|
begin
|
57
57
|
# TODO: Currently expects JPEG
|
58
|
+
video_file_path = image_file_path + "/#{image.external_identifier}.mp4"
|
58
59
|
image_file_path += "/#{image.external_identifier}.jpg"
|
59
60
|
raise "Image file already exists, will not overwrite: #{image_file_path}" if File.exist?(image_file_path)
|
60
61
|
|
61
62
|
image_data = harvester.harvest_image_data(image)
|
62
|
-
|
63
|
+
|
63
64
|
File.open(image_file_path, "wb") do |f|
|
64
65
|
f.write image_data
|
65
66
|
end
|
66
67
|
|
68
|
+
if image.media_type == "video"
|
69
|
+
raise "Video file already exists, will not overwrite: #{video_file_path}" if File.exist?(video_file_path)
|
70
|
+
video_data = harvester.harvest_video_data(image)
|
71
|
+
File.open(video_file_path, "wb") do |f|
|
72
|
+
f.write video_data
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
67
76
|
image.file_harvested_date = DateTime.now
|
68
77
|
image.save
|
69
78
|
puts "Harvested image #{image.id}, #{image_file_path}"
|
@@ -135,5 +144,83 @@ namespace :lentil do
|
|
135
144
|
end
|
136
145
|
end
|
137
146
|
end
|
147
|
+
|
148
|
+
desc "Get video urls from videos previously harvested"
|
149
|
+
task :restore_videos, [:image_service] => :environment do |t, args|
|
150
|
+
args.with_defaults(:image_service => 'Instagram')
|
151
|
+
|
152
|
+
harvester = Lentil::InstagramHarvester.new
|
153
|
+
|
154
|
+
lentilService = Lentil::Service.unscoped.where(:name => args[:image_service]).first
|
155
|
+
numUpdated = 0;
|
156
|
+
lentilService.images.unscoped.each do |image|
|
157
|
+
#Skip if media type already known i.e. was properly harvested
|
158
|
+
next if !image.media_type.blank?
|
159
|
+
|
160
|
+
meta = image.original_metadata
|
161
|
+
obj = YAML.load(meta)
|
162
|
+
type = obj["type"]
|
163
|
+
video_url = image.video_url
|
164
|
+
if(type == "video")
|
165
|
+
video_url = obj["videos"]["standard_resolution"]["url"]
|
166
|
+
image.video_url = video_url
|
167
|
+
image.media_type = 'video'
|
168
|
+
image.save
|
169
|
+
numUpdated += 1
|
170
|
+
else
|
171
|
+
image.media_type = 'image'
|
172
|
+
image.save
|
173
|
+
numUpdated += 1
|
174
|
+
end
|
175
|
+
end
|
176
|
+
puts numUpdated.to_s + " record(s) updated"
|
177
|
+
end
|
178
|
+
|
179
|
+
desc "Dump image metadata for archiving"
|
180
|
+
task :dump_metadata, [:image_service, :base_directory] => :environment do |t, args|
|
181
|
+
args.with_defaults(:image_service => 'Instagram')
|
182
|
+
base_dir = args[:base_directory] || Lentil::Engine::APP_CONFIG["base_image_file_dir"] || nil
|
183
|
+
raise "Base directory is required" unless base_dir
|
184
|
+
|
185
|
+
lentilService = Lentil::Service.unscoped.where(:name => args[:image_service]).first
|
186
|
+
numArchived = 0;
|
187
|
+
lentilService.images.unscoped.each do |image|
|
188
|
+
begin
|
189
|
+
raise "Destination directory does not exist or is not a directory: #{base_dir}" unless File.directory?(base_dir)
|
190
|
+
|
191
|
+
image_file_path = "#{base_dir}/#{image.service.name}"
|
192
|
+
|
193
|
+
if !File.exist?(image_file_path)
|
194
|
+
Dir.mkdir(image_file_path)
|
195
|
+
else
|
196
|
+
raise "Service directory is not a directory: #{image_file_path}" unless File.directory?(image_file_path)
|
197
|
+
end
|
198
|
+
rescue => e
|
199
|
+
Rails.logger.error e.message
|
200
|
+
raise e
|
201
|
+
end
|
202
|
+
|
203
|
+
@jsonobj = JSON.parse(image.to_json)
|
204
|
+
@jsonobj.delete("id")
|
205
|
+
@jsonobj["tags"] = JSON.parse(image.tags.to_json)
|
206
|
+
@jsonobj["licenses"] = JSON.parse(image.licenses.to_json)
|
207
|
+
@jsonobj["licenses"].each do |lic|
|
208
|
+
lic.delete("id")
|
209
|
+
end
|
210
|
+
|
211
|
+
@jsonobj["like_votes"] = JSON.parse(image.like_votes.to_json)
|
212
|
+
@jsonobj["flags"] = JSON.parse(image.flags.to_json)
|
213
|
+
|
214
|
+
@jsonobj["service"] = JSON.parse(image.service.to_json).except("id")
|
215
|
+
@jsonobj["user"] = JSON.parse(image.user.to_json).except("id", "service_id")
|
216
|
+
|
217
|
+
image_file_path += "/#{image.external_identifier}.json"
|
218
|
+
File.open(image_file_path, "w") do |f|
|
219
|
+
f.write @jsonobj.to_json
|
220
|
+
numArchived += 1
|
221
|
+
end
|
222
|
+
end
|
223
|
+
puts "#{numArchived} image(s) metadata extracted"
|
224
|
+
end
|
138
225
|
end
|
139
226
|
end
|
data/test/dummy/db/schema.rb
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
#
|
12
12
|
# It's strongly recommended to check this file into your version control system.
|
13
13
|
|
14
|
-
ActiveRecord::Schema.define(:version =>
|
14
|
+
ActiveRecord::Schema.define(:version => 20141106172834) do
|
15
15
|
|
16
16
|
create_table "active_admin_comments", :force => true do |t|
|
17
17
|
t.string "resource_id", :null => false
|
@@ -90,6 +90,8 @@ ActiveRecord::Schema.define(:version => 20131205181204) do
|
|
90
90
|
t.datetime "donor_agreement_rejected"
|
91
91
|
t.boolean "do_not_request_donation", :default => false
|
92
92
|
t.datetime "last_donor_agreement_failure_date"
|
93
|
+
t.string "media_type"
|
94
|
+
t.string "video_url"
|
93
95
|
end
|
94
96
|
|
95
97
|
add_index "lentil_images", ["external_identifier"], :name => "index_images_on_external_identifier"
|
@@ -282,3 +282,76 @@ three:
|
|
282
282
|
donor_agreement_failed: 0
|
283
283
|
failed_file_checks: 0
|
284
284
|
file_last_checked:
|
285
|
+
|
286
|
+
video:
|
287
|
+
description: 'six #hunttesting'
|
288
|
+
created_at: 2013-04-16 16:16:16.273698000 Z
|
289
|
+
updated_at: 2013-04-16 16:16:16.481430000 Z
|
290
|
+
like_votes_count: 0
|
291
|
+
url: http://instagram.com/p/k5LhuktiSC/
|
292
|
+
user: bd
|
293
|
+
state: 1
|
294
|
+
external_identifier: '853651752801735775_3292244'
|
295
|
+
long_url: http://scontent-b.cdninstagram.com/hphotos-xfa1/t51.2885-15/915706_724481087621112_1586087020_n.jpg
|
296
|
+
original_datetime: 2013-04-16 15:58:34.000000000 Z
|
297
|
+
staff_like: true
|
298
|
+
moderator_id:
|
299
|
+
moderated_at:
|
300
|
+
second_moderation: false
|
301
|
+
wins_count: 5
|
302
|
+
losses_count: 5
|
303
|
+
win_pct: 50
|
304
|
+
popular_score: 0
|
305
|
+
file_harvested_date:
|
306
|
+
file_harvest_failed: 0
|
307
|
+
donor_agreement_submitted_date:
|
308
|
+
donor_agreement_failed: 0
|
309
|
+
failed_file_checks: 0
|
310
|
+
file_last_checked:
|
311
|
+
original_metadata:
|
312
|
+
attribution:
|
313
|
+
tags:
|
314
|
+
- hunttesting
|
315
|
+
location:
|
316
|
+
comments:
|
317
|
+
count: 0
|
318
|
+
data: []
|
319
|
+
filter: Amaro
|
320
|
+
created_time: '1393448079'
|
321
|
+
link: http://instagram.com/p/k5LhuktiSC/
|
322
|
+
likes:
|
323
|
+
count: 0
|
324
|
+
data: []
|
325
|
+
images:
|
326
|
+
low_resolution:
|
327
|
+
url: http://distilleryimage8.s3.amazonaws.com/28b09b209f2811e38e831293e346cce0_6.jpg
|
328
|
+
width: 306
|
329
|
+
height: 306
|
330
|
+
thumbnail:
|
331
|
+
url: http://distilleryimage8.s3.amazonaws.com/28b09b209f2811e38e831293e346cce0_5.jpg
|
332
|
+
width: 150
|
333
|
+
height: 150
|
334
|
+
standard_resolution:
|
335
|
+
url: http://distilleryimage8.s3.amazonaws.com/28b09b209f2811e38e831293e346cce0_8.jpg
|
336
|
+
width: 612
|
337
|
+
height: 612
|
338
|
+
caption:
|
339
|
+
created_time: '1393448079'
|
340
|
+
text: ! 'six #hunttesting'
|
341
|
+
from:
|
342
|
+
username: bddnc
|
343
|
+
profile_picture: http://images.ak.instagram.com/profiles/anonymousUser.jpg
|
344
|
+
id: '1128023464'
|
345
|
+
full_name: bddnc
|
346
|
+
id: '664613117098338265'
|
347
|
+
type: image
|
348
|
+
id: '853651752801735775_3292244'
|
349
|
+
user:
|
350
|
+
username: bddnc
|
351
|
+
website: ''
|
352
|
+
profile_picture: http://images.ak.instagram.com/profiles/anonymousUser.jpg
|
353
|
+
full_name: bddnc
|
354
|
+
bio: ''
|
355
|
+
id: '1128023464'
|
356
|
+
video_url: 'http://scontent-b.cdninstagram.com/hphotos-xaf1/t50.2886-16/10814479_740198139394848_641606265_n.mp4'
|
357
|
+
media_type: 'video'
|
@@ -2,13 +2,15 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class ImagesShowIndexTest < ActionDispatch::IntegrationTest
|
4
4
|
|
5
|
-
setup do
|
6
|
-
visit(lentil.image_path lentil_images(:one))
|
7
|
-
end
|
8
|
-
|
9
5
|
# This is important otherwise there is some strange reloading that goes on
|
10
6
|
test "should have a class on the body" do
|
7
|
+
visit(lentil.image_path lentil_images(:one))
|
11
8
|
assert page.has_selector?('body.lentil-images_show')
|
12
9
|
end
|
10
|
+
|
11
|
+
test "video should have a video tag" do
|
12
|
+
visit(lentil.image_path lentil_images(:video))
|
13
|
+
assert page.has_selector?('video')
|
14
|
+
end
|
13
15
|
|
14
|
-
end
|
16
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -233,33 +233,41 @@
|
|
233
233
|
$img.parent().css( 'background-image', 'url(' + src + ')' );
|
234
234
|
|
235
235
|
if( loaded === count ) {
|
236
|
+
self._loadingComplete($imgs);
|
237
|
+
}
|
236
238
|
|
237
|
-
|
238
|
-
|
239
|
-
// the items
|
240
|
-
self.$items = self.$list.children( 'li' );
|
241
|
-
// make a copy of the items
|
242
|
-
self.$itemsCache = self.$items.clone();
|
243
|
-
// total number of items
|
244
|
-
self.itemsTotal = self.$items.length;
|
245
|
-
// the items that will be out of the grid
|
246
|
-
// actually the item's child (anchor element)
|
247
|
-
self.outItems= [];
|
248
|
-
self._layout( function() {
|
249
|
-
self._initEvents();
|
250
|
-
} );
|
251
|
-
// replace [options.step] items after [options.interval] time
|
252
|
-
// the items that go out are randomly chosen, while the ones that get in
|
253
|
-
// follow a "First In First Out" logic
|
254
|
-
self._start();
|
239
|
+
} ).bind('error', function() {
|
240
|
+
count--;
|
255
241
|
|
242
|
+
if( loaded === count ) {
|
243
|
+
self._loadingComplete($imgs);
|
256
244
|
}
|
245
|
+
}).attr( 'src', src );
|
257
246
|
|
258
|
-
} ).attr( 'src', src )
|
259
|
-
|
260
247
|
} );
|
261
248
|
|
262
249
|
},
|
250
|
+
_loadingComplete : function($imgs) {
|
251
|
+
var self = this;
|
252
|
+
$imgs.remove();
|
253
|
+
self.$el.removeClass( 'ri-grid-loading' );
|
254
|
+
// the items
|
255
|
+
self.$items = self.$list.children( 'li' );
|
256
|
+
// make a copy of the items
|
257
|
+
self.$itemsCache = self.$items.clone();
|
258
|
+
// total number of items
|
259
|
+
self.itemsTotal = self.$items.length;
|
260
|
+
// the items that will be out of the grid
|
261
|
+
// actually the item's child (anchor element)
|
262
|
+
self.outItems= [];
|
263
|
+
self._layout( function() {
|
264
|
+
self._initEvents();
|
265
|
+
} );
|
266
|
+
// replace [options.step] items after [options.interval] time
|
267
|
+
// the items that go out are randomly chosen, while the ones that get in
|
268
|
+
// follow a "First In First Out" logic
|
269
|
+
self._start();
|
270
|
+
},
|
263
271
|
_layout : function( callback ) {
|
264
272
|
|
265
273
|
var self = this;
|
@@ -643,6 +651,11 @@
|
|
643
651
|
}
|
644
652
|
|
645
653
|
$el.next().remove();
|
654
|
+
var videos = $el.find("video");
|
655
|
+
if(videos.length !== 0) {
|
656
|
+
//Since it's a clone, have to start the event manually
|
657
|
+
videos[0].play();
|
658
|
+
}
|
646
659
|
$el.parent().data( 'active', false );
|
647
660
|
|
648
661
|
}, t );
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lentil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Casden
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2015-03-03 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
@@ -19,14 +19,14 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - "~>"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 3.2.
|
22
|
+
version: 3.2.21
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 3.2.
|
29
|
+
version: 3.2.21
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: jquery-rails
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -61,14 +61,14 @@ dependencies:
|
|
61
61
|
requirements:
|
62
62
|
- - "~>"
|
63
63
|
- !ruby/object:Gem::Version
|
64
|
-
version: 3.
|
64
|
+
version: 3.4.1
|
65
65
|
type: :runtime
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
69
|
- - "~>"
|
70
70
|
- !ruby/object:Gem::Version
|
71
|
-
version: 3.
|
71
|
+
version: 3.4.1
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
73
|
name: meta_search
|
74
74
|
requirement: !ruby/object:Gem::Requirement
|
@@ -646,6 +646,7 @@ files:
|
|
646
646
|
- db/migrate/20130506204728_add_donor_agreement_rejected_to_images.rb
|
647
647
|
- db/migrate/20130506205348_add_do_not_request_donation_to_lentil_images.rb
|
648
648
|
- db/migrate/20131205181204_add_last_donor_agreement_failure_date_to_lentil_images.rb
|
649
|
+
- db/migrate/20141106172834_add_type_to_images.rb
|
649
650
|
- db/seeds.rb
|
650
651
|
- lib/generators/lentil/USAGE
|
651
652
|
- lib/generators/lentil/install_generator.rb
|
@@ -856,7 +857,8 @@ homepage: https://github.com/NCSU-Libraries/lentil
|
|
856
857
|
licenses:
|
857
858
|
- MIT
|
858
859
|
metadata: {}
|
859
|
-
post_install_message:
|
860
|
+
post_install_message: You may need to run 'bundle exec rake lentil:install:migrations'
|
861
|
+
to incorporate any new database migration files.
|
860
862
|
rdoc_options: []
|
861
863
|
require_paths:
|
862
864
|
- lib
|
@@ -872,7 +874,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
872
874
|
version: '0'
|
873
875
|
requirements: []
|
874
876
|
rubyforge_project:
|
875
|
-
rubygems_version: 2.4.
|
877
|
+
rubygems_version: 2.4.6
|
876
878
|
signing_key:
|
877
879
|
specification_version: 4
|
878
880
|
summary: lentil supports the harvesting of images from Instagram.
|