mirror of
https://github.com/iv-org/invidious.git
synced 2024-12-12 09:14:39 -05:00
Add video previews
This commit is contained in:
parent
1a9360ca75
commit
6d92775ab5
7
assets/css/videojs-vtt-thumbnails.css
Normal file
7
assets/css/videojs-vtt-thumbnails.css
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* videojs-vtt-thumbnails
|
||||||
|
* @version 0.0.13
|
||||||
|
* @copyright 2019 Chris Boustead <chris@forgemotion.com>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
.video-js.vjs-vtt-thumbnails{display:block}.video-js .vjs-vtt-thumbnail-display{position:absolute;transition:transform .1s, opacity .2s;bottom:85%;pointer-events:none;box-shadow:0 0 7px rgba(0,0,0,0.6)}
|
7
assets/js/videojs-vtt-thumbnails.min.js
vendored
Normal file
7
assets/js/videojs-vtt-thumbnails.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -3053,6 +3053,86 @@ get "/api/v1/stats" do |env|
|
|||||||
statistics.to_json
|
statistics.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# YouTube provides "storyboards", which are sprites containing of x * y
|
||||||
|
# preview thumbnails for individual scenes in a video.
|
||||||
|
# See https://support.jwplayer.com/articles/how-to-add-preview-thumbnails
|
||||||
|
get "/api/v1/storyboards/:id" do |env|
|
||||||
|
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
|
||||||
|
|
||||||
|
env.response.content_type = "application/json"
|
||||||
|
|
||||||
|
id = env.params.url["id"]
|
||||||
|
region = env.params.query["region"]?
|
||||||
|
|
||||||
|
client = make_client(YT_URL)
|
||||||
|
begin
|
||||||
|
video = get_video(id, PG_DB, proxies, region: region)
|
||||||
|
rescue ex : VideoRedirect
|
||||||
|
next env.redirect "/api/v1/storyboards/#{ex.message}"
|
||||||
|
rescue ex
|
||||||
|
env.response.status_code = 500
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
storyboards = video.storyboards
|
||||||
|
|
||||||
|
width = env.params.query["width"]?
|
||||||
|
height = env.params.query["height"]?
|
||||||
|
|
||||||
|
if !width && !height
|
||||||
|
response = JSON.build do |json|
|
||||||
|
json.object do
|
||||||
|
json.field "storyboards" do
|
||||||
|
generate_storyboards(json, id, storyboards, config, Kemal.config)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
next response
|
||||||
|
end
|
||||||
|
|
||||||
|
env.response.content_type = "text/vtt"
|
||||||
|
|
||||||
|
storyboard = storyboards.select { |storyboard| width == "#{storyboard[:width]}" || height == "#{storyboard[:height]}" }
|
||||||
|
|
||||||
|
if storyboard.empty?
|
||||||
|
env.response.status_code = 404
|
||||||
|
next
|
||||||
|
else
|
||||||
|
storyboard = storyboard[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
webvtt = <<-END_VTT
|
||||||
|
WEBVTT
|
||||||
|
|
||||||
|
|
||||||
|
END_VTT
|
||||||
|
|
||||||
|
start_time = 0.milliseconds
|
||||||
|
end_time = storyboard[:interval].milliseconds
|
||||||
|
|
||||||
|
storyboard[:storyboard_count].times do |i|
|
||||||
|
host_url = make_host_url(config, Kemal.config)
|
||||||
|
url = storyboard[:url].gsub("$M", i).gsub("https://i9.ytimg.com", host_url)
|
||||||
|
|
||||||
|
storyboard[:storyboard_height].times do |j|
|
||||||
|
storyboard[:storyboard_width].times do |k|
|
||||||
|
webvtt += <<-END_CUE
|
||||||
|
#{start_time}.000 --> #{end_time}.000
|
||||||
|
#{url}#xywh=#{storyboard[:width] * k},#{storyboard[:height] * j},#{storyboard[:width]},#{storyboard[:height]}
|
||||||
|
|
||||||
|
|
||||||
|
END_CUE
|
||||||
|
|
||||||
|
start_time += storyboard[:interval].milliseconds
|
||||||
|
end_time += storyboard[:interval].milliseconds
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
webvtt
|
||||||
|
end
|
||||||
|
|
||||||
get "/api/v1/captions/:id" do |env|
|
get "/api/v1/captions/:id" do |env|
|
||||||
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
|
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
|
||||||
|
|
||||||
@ -3145,7 +3225,7 @@ get "/api/v1/captions/:id" do |env|
|
|||||||
text = "<v #{md["name"]}>#{md["text"]}</v>"
|
text = "<v #{md["name"]}>#{md["text"]}</v>"
|
||||||
end
|
end
|
||||||
|
|
||||||
webvtt = webvtt + <<-END_CUE
|
webvtt += <<-END_CUE
|
||||||
#{start_time} --> #{end_time}
|
#{start_time} --> #{end_time}
|
||||||
#{text}
|
#{text}
|
||||||
|
|
||||||
@ -5054,6 +5134,13 @@ get "/ggpht/*" do |env|
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
options "/sb/:id/:storyboard/:index" do |env|
|
||||||
|
env.response.headers.delete("Content-Type")
|
||||||
|
env.response.headers["Access-Control-Allow-Origin"] = "*"
|
||||||
|
env.response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS"
|
||||||
|
env.response.headers["Access-Control-Allow-Headers"] = "Content-Type, Range"
|
||||||
|
end
|
||||||
|
|
||||||
get "/sb/:id/:storyboard/:index" do |env|
|
get "/sb/:id/:storyboard/:index" do |env|
|
||||||
id = env.params.url["id"]
|
id = env.params.url["id"]
|
||||||
storyboard = env.params.url["storyboard"]
|
storyboard = env.params.url["storyboard"]
|
||||||
|
@ -281,7 +281,7 @@ struct Video
|
|||||||
generate_thumbnails(json, self.id, config, kemal_config)
|
generate_thumbnails(json, self.id, config, kemal_config)
|
||||||
end
|
end
|
||||||
json.field "storyboards" do
|
json.field "storyboards" do
|
||||||
generate_storyboards(json, self.storyboards, config, kemal_config)
|
generate_storyboards(json, self.id, self.storyboards, config, kemal_config)
|
||||||
end
|
end
|
||||||
|
|
||||||
description_html, description = html_to_content(self.description)
|
description_html, description = html_to_content(self.description)
|
||||||
@ -1348,11 +1348,12 @@ def generate_thumbnails(json, id, config, kemal_config)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_storyboards(json, storyboards, config, kemal_config)
|
def generate_storyboards(json, id, storyboards, config, kemal_config)
|
||||||
json.array do
|
json.array do
|
||||||
storyboards.each do |storyboard|
|
storyboards.each do |storyboard|
|
||||||
json.object do
|
json.object do
|
||||||
json.field "url", storyboard[:url]
|
json.field "url", "/api/v1/storyboards/#{id}?width=#{storyboard[:width]}&height=#{storyboard[:height]}"
|
||||||
|
json.field "templateUrl", storyboard[:url]
|
||||||
json.field "width", storyboard[:width]
|
json.field "width", storyboard[:width]
|
||||||
json.field "height", storyboard[:height]
|
json.field "height", storyboard[:height]
|
||||||
json.field "count", storyboard[:count]
|
json.field "count", storyboard[:count]
|
||||||
|
@ -217,6 +217,10 @@ if (bpb) {
|
|||||||
player.httpSourceSelector();
|
player.httpSourceSelector();
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
player.vttThumbnails({
|
||||||
|
src: 'api/v1/storyboards/<%= video.id %>?height=90'
|
||||||
|
});
|
||||||
|
|
||||||
<% if !params.listen && params.annotations %>
|
<% if !params.listen && params.annotations %>
|
||||||
var video_container = document.getElementById('player');
|
var video_container = document.getElementById('player');
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
|
@ -2,12 +2,14 @@
|
|||||||
<link rel="stylesheet" href="/css/videojs-http-source-selector.css">
|
<link rel="stylesheet" href="/css/videojs-http-source-selector.css">
|
||||||
<link rel="stylesheet" href="/css/videojs.markers.min.css">
|
<link rel="stylesheet" href="/css/videojs.markers.min.css">
|
||||||
<link rel="stylesheet" href="/css/videojs-share.css">
|
<link rel="stylesheet" href="/css/videojs-share.css">
|
||||||
|
<link rel="stylesheet" href="/css/videojs-vtt-thumbnails.css">
|
||||||
<script src="/js/video.min.js"></script>
|
<script src="/js/video.min.js"></script>
|
||||||
<script src="/js/videojs-contrib-quality-levels.min.js"></script>
|
<script src="/js/videojs-contrib-quality-levels.min.js"></script>
|
||||||
<script src="/js/videojs-http-source-selector.min.js"></script>
|
<script src="/js/videojs-http-source-selector.min.js"></script>
|
||||||
<script src="/js/videojs.hotkeys.min.js"></script>
|
<script src="/js/videojs.hotkeys.min.js"></script>
|
||||||
<script src="/js/videojs-markers.min.js"></script>
|
<script src="/js/videojs-markers.min.js"></script>
|
||||||
<script src="/js/videojs-share.min.js"></script>
|
<script src="/js/videojs-share.min.js"></script>
|
||||||
|
<script src="/js/videojs-vtt-thumbnails.min.js"></script>
|
||||||
|
|
||||||
<% if params.annotations %>
|
<% if params.annotations %>
|
||||||
<link rel="stylesheet" href="/css/videojs-youtube-annotations.min.css">
|
<link rel="stylesheet" href="/css/videojs-youtube-annotations.min.css">
|
||||||
|
@ -93,6 +93,20 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-vtt-thumbnails.min.js">videojs-vtt-thumbnails.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://www.jclark.com/xml/copying.txt">Expat</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/chrisboustead/videojs-vtt-thumbnails"><%= translate(locale, "source") %></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="/js/videojs-youtube-annotations.min.js">videojs-youtube-annotations.min.js</a>
|
<a href="/js/videojs-youtube-annotations.min.js">videojs-youtube-annotations.min.js</a>
|
||||||
|
Loading…
Reference in New Issue
Block a user