Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Remove harsh video restriction and add video duration (#1811)
* Remove harsh video restriction and add video duration

* Fix video meta data and tests

* Modify video tests

* Rescue video duration fetch error

* Change log to puts in test
  • Loading branch information
benhalpern committed Feb 16, 2019
1 parent 28bac35 commit bce0b4f
Show file tree
Hide file tree
Showing 22 changed files with 181 additions and 43 deletions.
1 change: 1 addition & 0 deletions Gemfile
Expand Up @@ -58,6 +58,7 @@ gem "jquery-rails", "~> 4.3"
gem "kaminari", "~> 1.1"
gem "libhoney", "~> 1.11"
gem "liquid", "~> 4.0"
gem "ffprober", "~> 0.5"
gem "nokogiri", "~> 1.10"
gem "octokit", "~> 4.13"
gem "omniauth", "~> 1.9"
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Expand Up @@ -311,6 +311,7 @@ GEM
loofah (>= 2.0)
sax-machine (>= 1.0)
ffi (1.9.25)
ffprober (0.5.3)
figaro (1.1.1)
thor (~> 0.14)
fission (0.5.0)
Expand Down Expand Up @@ -979,6 +980,7 @@ DEPENDENCIES
fastly (~> 1.15)
fastly-rails (~> 0.8)
feedjira (~> 2.2)
ffprober (~> 0.5)
figaro (~> 1.1)
fix-db-schema-conflicts!
fog (~> 1.41)
Expand Down
77 changes: 77 additions & 0 deletions app/assets/images/video-camera.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions app/assets/javascripts/utilities/buildArticleHTML.js.erb
Expand Up @@ -98,7 +98,12 @@ function buildArticleHTML(article) {
} else if (article.class_name === "Article") {
readingTimeHTML = '<a href="'+article.path+'" class="article-reading-time">3 min read</a>'
}
var videoHTML = '';
if (article.cloudinary_video_url) {
videoHTML = '<a href="'+article.path+'" class="single-article-video-preview" style="background-image:url('+article.cloudinary_video_url+')"><div class="single-article-video-duration"><img src="<%= asset_path("video-camera.svg") %>" />'+article.video_duration_in_minutes+'</div></a>'
}
return '<div class="single-article single-article-small-pic">\
'+videoHTML+'\
'+orgHeadline+'\
<div class="small-pic">\
<a href="/'+profileUsername+'" class="small-pic-link-wrapper">\
Expand Down
30 changes: 30 additions & 0 deletions app/assets/stylesheets/articles.scss
Expand Up @@ -233,6 +233,36 @@
overflow: hidden;
text-overflow: ellipsis;
}
.single-article-video-preview {
img {
width: 100%;
}
position: relative;
padding-top: 56%;
display: block;
background: $black no-repeat center center;
background-size: cover;
&:hover {
opacity: 1;
}
.single-article-video-duration {
position: absolute;
bottom: 8px;
right: 7px;
background: rgba(0,0,0,0.8);
color: white;
border-radius: 3px;
padding: 2px 5px 3px;
font-size: 0.75em;
font-weight: 500;
img {
width: 12px;
height: 12px;
margin-right: 4px;
vertical-align: -1px;
}
}
}
.article-organization-headline {
display:block;
margin-bottom:calc(-1px - 0.6vw);
Expand Down
13 changes: 1 addition & 12 deletions app/controllers/internal/users_controller.rb
Expand Up @@ -55,22 +55,12 @@ def update_role
toggle_warn_user if user_params[:warn_user]
toggle_trust_user if user_params[:trusted_user]
toggle_ban_from_mentorship if user_params[:ban_from_mentorship]
toggle_video_permission if user_params[:video_permission]
end

def toggle_video_permission
if user_params[:video_permission] == "1"
@user.add_role :video_permission
else
@user.remove_role :video_permission
end
end

def toggle_ban_user
if user_params[:ban_user] == "1"
@user.add_role :banned
@user.remove_role :trusted
@user.remove_role :video_permission
create_note("banned", user_params[:note_for_current_role])
else
@user.remove_role :banned
Expand Down Expand Up @@ -189,7 +179,6 @@ def user_params
:note_for_mentorship_ban,
:note_for_current_role,
:reason_for_mentorship_ban,
:trusted_user,
:video_permission)
:trusted_user)
end
end
27 changes: 24 additions & 3 deletions app/models/article.rb
Expand Up @@ -49,6 +49,7 @@ class Article < ApplicationRecord
before_save :set_all_dates
before_save :calculate_base_scores
before_save :set_caches
before_save :fetch_video_duration
after_save :async_score_calc, if: :published
after_save :bust_cache
after_save :update_main_image_background_hex
Expand All @@ -75,7 +76,7 @@ class Article < ApplicationRecord
:main_image, :main_image_background_hex_color, :updated_at, :slug,
:video, :user_id, :organization_id, :video_source_url, :video_code,
:video_thumbnail_url, :video_closed_caption_track_url,
:published_at, :crossposted_at, :boost_states, :description, :reading_time)
:published_at, :crossposted_at, :boost_states, :description, :reading_time, :video_duration_in_seconds)
}

scope :limited_columns_internal_select, -> {
Expand Down Expand Up @@ -137,7 +138,8 @@ class Article < ApplicationRecord
enqueue: :trigger_delayed_index do
attributes :title, :path, :class_name, :comments_count, :reading_time,
:tag_list, :positive_reactions_count, :id, :hotness_score, :score,
:readable_publish_date, :flare_tag, :user_id, :organization_id
:readable_publish_date, :flare_tag, :user_id, :organization_id,
:cloudinary_video_url, :video_duration_in_minutes
attribute :published_at_int do
published_at.to_i
end
Expand Down Expand Up @@ -384,6 +386,25 @@ def all_series
user&.collections&.pluck(:slug)
end

def cloudinary_video_url
ApplicationController.helpers.cloudinary(video_thumbnail_url, 880)
end

def video_duration_in_minutes
minutes = (video_duration_in_seconds.to_i / 60) % 60
seconds = video_duration_in_seconds.to_i % 60
"#{minutes}:#{seconds}"
end

def fetch_video_duration
if video.present? && video_duration_in_seconds.zero?
info = Ffprober::Parser.from_url video
self.video_duration_in_seconds = info.json[:format][:duration].to_f
end
rescue StandardError => e
puts e.message
end

private

def update_notifications
Expand Down Expand Up @@ -454,7 +475,7 @@ def validate_video
if published && video_state == "PROGRESSING"
return errors.add(:published, "cannot be set to true if video is still processing")
end
if video.present? && !user.has_role?(:video_permission)
if video.present? && user.created_at > 2.weeks.ago
return errors.add(:video, "cannot be added member without permission")
end
end
Expand Down
1 change: 0 additions & 1 deletion app/models/role.rb
Expand Up @@ -25,7 +25,6 @@ class Role < ApplicationRecord
level_2_member
level_1_member
workshop_pass
video_permission
chatroom_beta_tester
banned_from_mentorship
comment_banned
Expand Down
2 changes: 1 addition & 1 deletion app/models/user.rb
Expand Up @@ -3,7 +3,7 @@ class User < ApplicationRecord

attr_accessor :scholar_email, :note, :ban_from_mentorship, :quick_match, :ban_user, :warn_user,
:note_for_mentorship_ban, :reason_for_mentorship_ban,
:note_for_current_role, :add_mentor, :add_mentee, :trusted_user, :video_permission
:note_for_current_role, :add_mentor, :add_mentee, :trusted_user

rolify
include AlgoliaSearch
Expand Down
4 changes: 2 additions & 2 deletions app/policies/video_policy.rb
@@ -1,9 +1,9 @@
class VideoPolicy < ApplicationPolicy
def new?
user.has_role?(:video_permission)
user.created_at < 2.weeks.ago if user.created_at
end

def create?
user.has_role?(:video_permission)
user.created_at < 2.weeks.ago if user.created_at
end
end
16 changes: 9 additions & 7 deletions app/views/articles/_single_story.html.erb
@@ -1,13 +1,15 @@
<div class="single-article single-article-small-pic">
<% if story.video.present? %>
<%= render "articles/video_player", meta_tags: false, article: story %>
<% if story.video.present? && story.video_thumbnail_url.present? %>
<a class="single-article-video-preview" style="background-image:url(<%= story.cloudinary_video_url %>)" >
<div class="single-article-video-duration"><img src="<%= asset_path("video-camera.svg") %>" /><%= story.video_duration_in_minutes %></div>
</a>
<% end %>
<% organization = story.organization %>
<% if organization && !@organization_article_index %>
<div class="article-organization-headline">
<a href="/<%= organization.slug %>" class="article-organization-headline-inner"><img src="<%= organization.profile_image_90 %>"><%= organization.name %></a><a class="org-headline-filler" href="<%= story.path %>">&nbsp;</a></div>
<% end %>
<a href="<%=story.user.path%>" class="small-pic-link-wrapper">
<a href="<%= story.user.path%>" class="small-pic-link-wrapper">
<div class="small-pic" >
<% if story.cached_tag_list_array.include?("hiring") && story.organization_id.present? && !@organization_article_index %>
<img src="<%= ProfileImage.new(story.organization).get(90) %>" alt="<%= story.organization.username %> profile" />
Expand All @@ -16,15 +18,15 @@
<% end %>
</div>
</a>
<a href="<%=story.path%>" class="small-pic-link-wrapper index-article-link" data-preload-image="<%=cloud_cover_url(story.main_image) %>" id="article-link-<%=story.id%>">
<a href="<%= story.path %>" class="small-pic-link-wrapper index-article-link" data-preload-image="<%=cloud_cover_url(story.main_image) %>" id="article-link-<%= story.id%>">
<div class="content">
<h3>
<%= render "articles/tag_identifier", story: story, tag: @tag %>
</h3>
</div>
</a>
<h4>
<a href="<%=story.user.path%>"><%= story.user.name %><%= story.readable_publish_date %></a>
<a href="<%= story.user.path %>"><%= story.user.name %><%= story.readable_publish_date %></a>

</h4>
<div class="tags">
Expand All @@ -34,13 +36,13 @@
</div>
<% if story.comments_count > 0 %>
<div class="article-engagement-count comments-count">
<a href="<%=story.path%>#comments">
<a href="<%= story.path %>#comments">
<img src="<%= asset_path("comments-bubble.png") %>" alt="chat" /><span class="engagement-count-number"><%= story.comments_count %></span>
</a>
</div>
<% end %>
<div class="article-engagement-count reactions-count" data-reaction-count data-reactable-id="<%= story.id %>">
<a href="<%=story.path%>">
<a href="<%= story.path %>">
<img src="<%= asset_path("reactions-stack.png") %>" alt="Reactions" /><span id="engagement-count-number-<%= story.id %>" class="engagement-count-number">
<%= story.positive_reactions_count %>
</span>
Expand Down
4 changes: 3 additions & 1 deletion app/views/articles/_video_player.html.erb
@@ -1,10 +1,11 @@
<div <% "itemscope itemtype=\"http://schema.org/VideoObject\"" if meta_tags %> class="video-player-header">
<div temscope itemtype="http://schema.org/VideoObject" class="video-player-header">
<% if meta_tags %>
<meta itemprop="uploadDate" content="<%= @article.published_at %>" />
<meta itemprop="name" content="<%= @article.title %>" />
<meta itemprop="description" content="<%= @article.description %>" />
<meta itemprop="thumbnailUrl" content="<%= cloudinary(article.video_thumbnail_url, 880) %>" />
<meta itemprop="contentUrl" content="<%= article.video_source_url %>" />
<meta itemprop="duration" content="<%= "PT%sM%sS" % article.video_duration_in_minutes.split(':') %>" />
<% end %>
<script src="//content.jwplatform.com/libraries/b1zWy2iv.js" async> </script>
<div id="video-player-<%= article.id %>" class="video-player"></div>
Expand Down Expand Up @@ -40,6 +41,7 @@
playerInstance.setup({
file: "<%= article.video_source_url %>",
mediaid: "<%= article.video_code %>",
autostart: <%= internal_navigation? %>,
image: "<%= cloudinary(article.video_thumbnail_url, 880) %>",
playbackRateControls: true,
tracks: [{
Expand Down
8 changes: 4 additions & 4 deletions app/views/dashboards/show.html.erb
Expand Up @@ -2,15 +2,15 @@

<div class="dashboard-container" id="user-dashboard">
<div class="actions">
<a class="action <%= 'active' if params[:which] == "organization" || params[:which].blank? %>" href="/dashboard">
<a class="action <%= "active" if params[:which] == "organization" || params[:which].blank? %>" href="/dashboard">
<span>POSTS</span>
<span>(<%= @user.articles_count %>)</span>
</a>
<a class="action <%= 'active' if params[:which] == "user_followers" || params[:which] == "organization_user_followers" %>" href="/dashboard/user_followers">
<a class="action <%= "active" if params[:which] == "user_followers" || params[:which] == "organization_user_followers" %>" href="/dashboard/user_followers">
<span>FOLLOWERS</span>
<span>(<%= @user.followers_count %>)</span>
</a>
<a class="action <%= 'active' if params[:which].to_s.include?("following") %>" href="/dashboard/following">
<a class="action <%= "active" if params[:which].to_s.include?("following") %>" href="/dashboard/following">
<span>FOLLOWING</span>
<span>(<%= @user.following_users_count + @user.following_tags_count %>)</span>
</a>
Expand Down Expand Up @@ -78,7 +78,7 @@
<% end %>
<% elsif @articles.any? %>
<%= render "analytics" %>
<% if current_user.has_role?(:video_permission) %>
<% if current_user.created_at < 2.weeks.ago %>
<a class="video-upload-cta" href="/videos/new" data-no-instant>
Upload a Video 🎥
</a>
Expand Down
2 changes: 0 additions & 2 deletions app/views/internal/users/show.html.erb
Expand Up @@ -52,8 +52,6 @@
<%= form_for [:internal, @user] do |f| %>
<p>Add Trusted Role (Community Moderator)
<%= f.check_box :trusted_user, checked: @user.trusted %></p>
<p>Allow Video Uploads
<%= f.check_box :video_permission, checked: @user.has_role?(:video_permission) %> </p>
<%= f.submit "Update Privileges" %>
<% end %>
<% else %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/videos/new.html.erb
Expand Up @@ -18,7 +18,7 @@
key: "video-upload__#{SecureRandom.hex}",
key_starts_with: "video-upload__",
acl: "public-read",
max_file_size: (current_user.has_role?(:super_admin) ? 15000 : 3500).megabytes,
max_file_size: (current_user.has_role?(:super_admin) ? 20000 : 6000).megabytes,
id: "s3-uploader",
class: "upload-form",
data: {:key => :val} do %>
Expand Down

0 comments on commit bce0b4f

Please sign in to comment.