Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement mp4 provider for videos #266

Merged
merged 8 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added app/assets/images/posters/fallback.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/clients/youtube/playlist_items.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def all(playlist_id:)
thumbnail_md: metadata.snippet.thumbnails.high&.url,
thumbnail_lg: metadata.snippet.thumbnails.standard&.url,
thumbnail_xl: metadata.snippet.thumbnails.maxres&.url,
video_provider: :youtube,
video_id: metadata.contentDetails.videoId
})
end
Expand Down
8 changes: 7 additions & 1 deletion app/javascript/controllers/video_player_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ export default class extends Controller {
playbackRateOptions = [1, 1.25, 1.5, 1.75, 2]

connect () {
const providerOptions = {}

if (this.hasProviderValue) {
providerOptions.provider = this.providerValue
}

this.player = new Vlitejs(this.playerTarget, {
provider: this.hasProviderValue ? this.providerValue : 'youtube',
...providerOptions,
options: {
poster: this.posterValue,
controls: true
Expand Down
61 changes: 49 additions & 12 deletions app/models/talk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,15 @@ class Talk < ApplicationRecord
validates :language, presence: true,
inclusion: {in: Language.alpha2_codes, message: "%{value} is not a valid IS0-639 alpha2 code"}

# scopes
scope :with_topics, -> { joins(:talk_topics) }
scope :without_topics, -> { where.missing(:talk_topics) }

# delegates
delegate :name, to: :event, prefix: true, allow_nil: true

# enums
enum :video_provider, %w[youtube mp4].index_by(&:itself)

# attributes
attribute :video_provider, default: :youtube

# jobs
performs :update_from_yml_metadata!, queue_as: :low

Expand Down Expand Up @@ -110,7 +112,7 @@ def analyze_talk_topics!
scope :with_topics, -> { joins(:talk_topics) }

scope :with_essential_card_data, -> do
select(:id, :slug, :title, :date, :thumbnail_sm, :thumbnail_lg, :video_id, :event_id, :language)
select(:id, :slug, :title, :date, :thumbnail_sm, :thumbnail_lg, :video_id, :video_provider, :event_id, :language)
.includes(:speakers, :event)
end

Expand Down Expand Up @@ -148,23 +150,51 @@ def to_meta_tags
end

def thumbnail_xs
self[:thumbnail_xs].presence || "https://i.ytimg.com/vi/#{video_id}/default.jpg"
thumbnail(:thumbnail_xs)
end

def thumbnail_sm
self[:thumbnail_sm].presence || "https://i.ytimg.com/vi/#{video_id}/mqdefault.jpg"
thumbnail(:thumbnail_sm)
end

def thumbnail_md
self[:thumbnail_md].presence || "https://i.ytimg.com/vi/#{video_id}/hqdefault.jpg"
thumbnail(:thumbnail_md)
end

def thumbnail_lg
self[:thumbnail_lg].presence || "https://i.ytimg.com/vi/#{video_id}/sddefault.jpg"
thumbnail(:thumbnail_lg)
end

def thumbnail_xl
self[:thumbnail_xl].presence || "https://i.ytimg.com/vi/#{video_id}/maxresdefault.jpg"
thumbnail(:thumbnail_xl)
end

def fallback_thumbnail
"/assets/#{Rails.application.assets.load_path.find("posters/fallback.png").digested_path}"
end

def thumbnail(size = :thumbnail_lg)
if self[size].present?
return self[size] if self[size].start_with?("https://")

if (asset = Rails.application.assets.load_path.find(self[size]))
return "/assets/#{asset.digested_path}"
else
return fallback_thumbnail
end
end

return fallback_thumbnail if video_provider != "youtube"

youtube = {
thumbnail_xs: "default",
thumbnail_sm: "mqdefault",
thumbnail_md: "hqdefault",
thumbnail_lg: "sddefault",
thumbnail_xl: "maxresdefault"
}

"https://i.ytimg.com/vi/#{video_id}/#{youtube[size]}.jpg"
end

def related_talks(limit: 6)
Expand Down Expand Up @@ -215,18 +245,25 @@ def update_from_yml_metadata!(event: nil)
return
end

date = static_metadata.try(:date) ||
event.start_date ||
event.end_date ||
static_metadata.published_at ||
Date.parse("#{static_metadata.year}-01-01")

assign_attributes(
event: event,
title: static_metadata.title,
description: static_metadata.description,
date: static_metadata.try(:date) || static_metadata.published_at || Date.parse("#{static_metadata.year}-01-01"),
date: date,
thumbnail_xs: static_metadata.thumbnail_xs || "",
thumbnail_sm: static_metadata.thumbnail_sm || "",
thumbnail_md: static_metadata.thumbnail_md || "",
thumbnail_lg: static_metadata.thumbnail_lg || "",
thumbnail_xl: static_metadata.thumbnail_xl || "",
language: static_metadata.language || Language::DEFAULT,
slides_url: static_metadata.slides_url
slides_url: static_metadata.slides_url,
video_provider: static_metadata.video_provider || :youtube
)

self.speakers = Array.wrap(static_metadata.speakers).reject(&:blank?).map { |speaker_name|
Expand Down
1 change: 1 addition & 0 deletions app/models/youtube/null_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def cleaned
event_name: @event_name,
published_at: @metadata.published_at,
description: @metadata.description,
video_provider: :youtube,
video_id: @metadata.video_id
}
)
Expand Down
1 change: 1 addition & 0 deletions app/models/youtube/video_metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def cleaned
event_name: @event_name,
published_at: @metadata.published_at,
description: description,
video_provider: :youtube,
video_id: @metadata.video_id
}
)
Expand Down
1 change: 1 addition & 0 deletions app/models/youtube/video_metadata_baltic_ruby_2024.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def cleaned
event_name: @event_name,
published_at: @metadata.published_at,
description: description_without_speaker,
video_provider: :youtube,
video_id: @metadata.video_id
}
)
Expand Down
1 change: 1 addition & 0 deletions app/models/youtube/video_metadata_rails_world.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def cleaned
event_name: @event_name,
published_at: @metadata.published_at,
description: description,
video_provider: :youtube,
video_id: @metadata.video_id
}
)
Expand Down
7 changes: 4 additions & 3 deletions app/views/talks/_card_horizontal.html.erb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<%# locals: (talk:, current_talk: nil, compact: false) -%>

<% active = talk == current_talk %>

<div class="<%= class_names("w-full flex items-center gap-2", "border border-secondary rounded-lg p-1": active) %>" id="<%= dom_id(talk, :card_horizontal) %>" data-talk-horizontal-card>
<%= link_to talk_path(talk),
class: "flex aspect-video shrink-0 relative w-28" do %>
<%= image_tag talk.thumbnail_sm, srcset: ["#{talk.thumbnail_lg} 2x"], id: dom_id(talk), class: "w-full h-auto object-cover", loading: :lazy %>
<%= link_to talk_path(talk), class: "flex aspect-video shrink-0 relative w-28" do %>
<%= image_tag talk.thumbnail_sm, srcset: ["#{talk.thumbnail_lg} 2x"], id: dom_id(talk), class: "w-full h-auto object-cover", style: "view-transition-name: #{dom_id(talk, :image)}#{active ? "active" : ""}", loading: :lazy %>
<% end %>

<div class="flex flex-col gap-2 text-sm">
<%= link_to talk_path(talk), class: "link link-ghost" do %>
<%= content_tag :div, talk.title, class: "font-semibold line-clamp-2 mt-1" %>
Expand Down
24 changes: 13 additions & 11 deletions app/views/talks/_talk.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@
data: {
controller: "video-player",
video_player_poster_value: talk.thumbnail_lg,
video_player_provider_value: "youtube",
video_player_provider_value: (talk.video_provider == "mp4") ? nil : talk.video_provider,
video_player_src_value: talk.video_id
} do %>

<div <%= tag.attributes(
class: "aspect-video banner-img card-horizontal-img relative",
style: "view-transition-name: #{dom_id(talk, :image)}"
) %>>

<%= content_tag :div, "",
class: "image",
id: dom_id(talk, :youtube),
data: {video_player_target: "player",
youtube_id: talk.video_id} %>
<div class="aspect-video banner-img card-horizontal-img relative" style="view-transition-name: <%= dom_id(talk, :image) %>">
<% if talk.video_provider == "mp4" %>
<video id="player" data-video-player-target="player" src="<%= talk.video_id %>"></video>
<% elsif talk.video_provider == "youtube" %>
<div
class="image"
id="<%= dom_id(talk, :youtube) %>"
data-video-player-target="player"
data-youtube-id="<%= talk.video_id %>"></div>
<% else %>
Provider <%= talk.video_provider %> is not configured.
<% end %>
</div>

<div class="py-4 flex flex-col gap-4">
Expand Down
11 changes: 11 additions & 0 deletions data/ancient-city-ruby/ancient-city-ruby-2013/videos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
This talk will answer the "why" by sharing my experience of passing through the five stages of grief (denial, anger, bargaining, depression, and acceptance) as I learned TDD, and how acceptance grew to love.

You will walk away from the talk with techniques for maintaining and strengthening your relationship with TDD. Test frameworks and languages may come and go, but the fundamentals and value of TDD remain.
video_provider: youtube
video_id: nBtO1UOK9Hs

- title: "Insight, Intuition and Programming"
Expand All @@ -33,6 +34,7 @@
the next, well, there it is. One minute you haven't a clue as to why the program
is doing that and the next it is all just obvious. And we have all seen code that
is wonderful or horrible in some indescribable way."
video_provider: youtube
video_id: rQp1CFJxgs0

- title: "Impressive Ruby Productivity with Vim and Tmux"
Expand All @@ -49,6 +51,7 @@
format and refactor your code with macros, remote pair program, and more, all
without leaving the terminal. Come prepared to learn and ask questions; this is
serious business.
video_provider: youtube
video_id: 9jzWDr24UHQ

- title: "Distributed Patterns in Ruby"
Expand All @@ -63,6 +66,7 @@
is a matter of how you handle two things: data distribution and message passing.
This talk is over a few ways of solving both: distributed data structures and
messaging patterns."
video_provider: youtube
video_id: Adu_dbcnUHA

- title: "How to Fail at Background Jobs"
Expand All @@ -80,6 +84,7 @@
jobs? Are we talking about "simple" asynchronous method calls on models or should
we build "pure" workers with only the knowledge of a single task? What does "idempotent"
mean again? Please allow me to enliven the debates.
video_provider: youtube
video_id: dkFwNEFr9cg

- title: "Building a mocking library"
Expand All @@ -92,6 +97,7 @@
This talk is not about testing, nor is it really about mocking. However, analyzing a mock object library is a great way to showcase advanced Ruby topics. Have you ever wondered exactly how a mock object library does what it does? You can understand it!

This talk uses a simplified mock object library as the basis for delving into topics such as metaprogramming and the Ruby object model. The goal is to increase the knowledge of these topics in the Ruby community. With this know--how, you will be better suited to build from and contribute to common Ruby tools that use them.
video_provider: youtube
video_id: 2aYdtS7FZJA

- title: "This is Your Brain on Software"
Expand All @@ -104,6 +110,7 @@
Developers are rational thinkers who take objective decisions. Yeah, sure. If that is the case, how can we disagree on so many things?

Examples are all around. Why do Rubyists and Java developers despise each others' designs? Why do people try hard to fit static typing and distributed environments? Why do Windows programmers loathe the command line? Let me try answering these questions, with a few hints from cognitive psychology.
video_provider: youtube
video_id: v9Gkq9-dnlU

- title: "Live Coding with Ben"
Expand All @@ -121,6 +128,7 @@
- Whether the Law of Demeter should be followed religiously, and what it means if that's hard to do.
- Why fast tests are usually good tests, and vice versa.
- Audience participation is strongly encouraged, as is stealing the speaker's Vim tricks for your own use.
video_provider: youtube
video_id: C0H-LyZy9Ko

- title: "The Magic Tricks of Testing"
Expand All @@ -134,6 +142,7 @@
Tests are supposed to save us money. How is it, then, that many times they become millstones around our necks, gradually morphing into fragile, breakable things that raise the cost of change?

We write too many tests and we test the wrong kinds of things. This talk strips away the veil and offers simple, practical guidelines for choosing what to test and how to test it. Finding the right testing balance isn't magic, it's a magic trick; come and learn the secret of writing stable tests that protect your application at the lowest possible cost.
video_provider: youtube
video_id: qPfQM4w4I04

- title: "Pairing is Caring"
Expand All @@ -151,6 +160,7 @@
important to maintaining the health of the Ruby community. Whether you work solo
or you pair regularly, you should leave this talk empowered and excited to broaden
your pair-programming horizons.
video_provider: youtube
video_id: zCzc5W7vHQg

- title: "Hacking with Gems"
Expand All @@ -163,4 +173,5 @@
What's the worst that could happen if your app has a dependency on a malicious gem? How easy would it be to write a gem that could compromise a box?

Much of the Ruby community blindly trusts our gems. This talk will make you second--guess that trust, and show you how to vet gems that you do choose to use.
video_provider: youtube
video_id: UksbZx4ph8E
11 changes: 11 additions & 0 deletions data/ancient-city-ruby/ancient-city-ruby-2014/videos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
binds of hierarchy, class, status and the distortions of those we choose to associate
ourselves? Let's take some time to remember who we are, where we are going and
discover, perhaps, why we are here.
video_provider: youtube
video_id: _oTEnczCS0s

# Sponsor Lightning Talks
Expand All @@ -47,6 +48,7 @@
Gone are the days when "is it tested?" was a boolean question. It no longer makes sense for a single test suite to accomplish numerous objectives, because the design of our tests are so influenced by the benefit we hope to realize from them. What's less clear to most developers is the best approach to breaking a test suite up.

This talk will introduce a testing architecture that's appropriate for the post-monolithic age of Ruby application development. We'll discuss why each test suite can provide at most one type of confidence and one type of feedback. I'll introduce a set of five narrow, focused types of test suites and explore how each of their roles can combine to provide all of the value that test automation can hope to offer. Together, we'll gain the ability to discuss the value of each test with much greater precision and subtlety.
video_provider: youtube
video_id: vkAfGHd7sZY

# Sponsor Lightning Talks
Expand All @@ -69,6 +71,7 @@
Many cry "overkill" when design principles are applied to trivial problems. And for good reason: in the context of work, excessive embellishment gets us into trouble. Complexity costs us time and money.

This talk explores how stepping outside of the realm of work and applying outrageous engineering practices to toy problems can deepen our understanding of the trade-offs that we make. Comically simple problems provide the perfect ground for developing actionable heuristics which can be applied to those monstrous complexities that we face in the real world.
video_provider: youtube
video_id: GTpZ0ffQrIE

# Sponsor Lightning Talks
Expand All @@ -89,6 +92,7 @@
total test coverage as painlessly as possible. You will learn how to stay sane
in the face of insane testing conditions, and how to use these tests to deconstruct
a monolith app. When life gives you a big ball of mud, write a big ball of tests."
video_provider: youtube
video_id: MdtfcLJwOf0

# Sponsor Lightning Talks
Expand All @@ -105,6 +109,7 @@
By now, we've all written JSON APIs in Rails. But how do you write fast, testable and sane APIs? I'll guide you through the trials of designing and building awesome, scalable APIs. We'll cover rails-api, activemodelserializers, and all the associated goodness that our ecosystem has to offer.

I'll speak on the approaches to authentication, how to ensure we remain good REST/HTTP citizens and maybe if I have time I'll share some of my top secret beard grooming tips!
video_provider: youtube
video_id: dUPp4DhFLnY

## Day 2 - 2014-04-04
Expand Down Expand Up @@ -132,6 +137,7 @@
remove the opacity around getting contributions upstreamed and how you can have
meaningful discussions with the implementers about the language we all know and
love. Help us make Ruby better."
video_provider: youtube
video_id: Vl5ASs3FtRw

# Lightning Talks
Expand All @@ -150,6 +156,7 @@
* Explain Plans
* Extensions
* More
video_provider: youtube
video_id: occqUdd7t4E

# Lightning Talks
Expand All @@ -168,6 +175,7 @@
from the Python world as well. In this talk, I'll provide a quick introduction
to the language. I'll provide just a quick overview of the language syntactically,
as well as cover some areas where it differs wildly from Ruby.
video_provider: youtube
video_id: rS5aeUi1sZs

# Lunch
Expand All @@ -183,6 +191,7 @@
talk, we will learn techniques for speeding up our code, fetching data from the
network, and doing image recognition, all in Ruby. Let's harness the power of
Sauron's Eye (my webcam) together!
video_provider: youtube
video_id: csN-NYFba0U

# Lightning Talks
Expand All @@ -197,6 +206,7 @@
Security is important. Yet, it's where a lot of web developers have little to no experience. We'll look at a whole range of opportunistic attack vectors that can be used against web applications, and how we can protect us against them.

This talk will include one currently undisclosed attack (at the time of writing).
video_provider: youtube
video_id: u_Le8-WsSs8

# Sponsor Lightning Talks
Expand All @@ -215,4 +225,5 @@
"HONEY! The baby needs a diaper change."

How do you balance all the distractions with raising children and still be able to deliver at your job? As Ruby developers, it's something that many of us can relate to but few really talk openly about. I work full-time at Engine Yard, create videos for Code TV, and also maintain RailsInstaller. All of that needs to balance nicely with my family and this talk will explore some of the problems I've faced and how I address them.
video_provider: youtube
video_id: F62cJHu53xc
Loading