Custom chapters with Vimeo Player API
I’ve just implemented Video timestamp navigation on videos embeded on SupeRails:
I was inspired by Chapters on Youtube:
In my app I embed videos with Vimeo.
To navigate to a timestamp in the vimeo player, you need to use the https://github.com/vimeo/player.js API.
First, install the package https://github.com/vimeo/player.js
./bin/importmap pin @vimeo/player
rails g stimulus vimeo
Stimulus controller to click play
, or navigate to a timestamp:
// app/javascript/controllers/vimeo_controller.js
import { Controller } from "@hotwired/stimulus"
import Player from '@vimeo/player';
// Connects to data-controller="vimeo"
export default class extends Controller {
static targets = ["player"]
connect() {
// continue only if the embedded video is from Vimeo
try {
this.player = new Player(this.playerTarget);
} catch {}
}
play(event) {
event.preventDefault()
this.player.play()
}
setCurrentTime(event) {
event.preventDefault()
this.player.setCurrentTime(event.target.dataset.time)
}
}
Embed a vimeo player, and add play and chapter navigation buttons:
<div data-controller="vimeo">
<iframe src="https://player.vimeo.com/video/1023706220?h=7e9bb172b6"
frameborder="0"
data-vimeo-target="player"
allowfullscreen>
<button data-action="click->vimeo#play">play</button>
<button data-action="vimeo#setCurrentTime" data-time="40">40</button>
<button data-action="vimeo#setCurrentTime" data-time="90">90</button>
</div>
Parse timestamps from text #
To add timestamps/chapters on Youtube, you simply edit a video description and type in the timestamps.
Next, Youtube parses your video description and extracts the timestamp time
and description
values.
We can parse a video description with Regex, and turn timestamps into buttons:
# app/helpers/application_helper.rb
# find all timestamps (0:00, 5:31, etc) in a text and convert them to buttons
def timestamps_to_buttons(text)
text.gsub(/(\d+:\d+)/) do |match|
time = match.split(':').map(&:to_i)
seconds = time[0] * 60 + time[1]
"<button data-action=\"vimeo#setCurrentTime\" data-time=\"#{seconds}\" style=\"color: blue;\">#{match}</button>"
end
end
You can even turn the timestamps & titles into JSON:
# app/helpers/application_helper.rb
def timestamps_array_from_text(text)
text.scan(/(\d+:\d+)\s(.+)/).map do |match|
time = match[0].split(':').map(&:to_i)
seconds = (time[0] * 60) + time[1]
{ human_time: match[0], time: seconds, text: match[1] }
end
end
Test the parser:
test 'timestamps_array_from_text' do
text = "hello world 0:00 Introduction\n0:10 First section\n2:30 Second section"
expected = [
{ human_time: '0:00', time: 0, text: 'Introduction' },
{ human_time: '0:10', time: 10, text: 'First section' },
{ human_time: '2:30', time: 150, text: 'Second section' }
]
assert_equal expected, timestamps_array_from_text(text)
end
Finally, display styled, clickable timestamps anywhere on your page (but within data-controller="vimeo"
):
<ul>
<% timestamps_array_from_text(text).each do |timestamp| %>
<li>
<button title="<%= timestamp[:text] %>" style="color: blue" data-action="vimeo#setCurrentTime" data-time="<%= timestamp[:time] %>"><%= timestamp[:human_time] %></button>
<%= timestamp[:text] %>
</li>
<% end %>
</ul>
That’s it! Custom chapter navigation works!
Did you like this article? Did it save you some time?