summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorOmar Roth <omarroth@protonmail.com>2019-05-02 14:20:19 -0500
committerOmar Roth <omarroth@protonmail.com>2019-05-02 14:36:32 -0500
commit6d92775ab546969230366b5bddbe51d36f73e7c7 (patch)
treed35430170d535d7e0dd5454e6edce3471837b75f /src
parent1a9360ca754e684947df566ad8d3c6f0deec8664 (diff)
downloadinvidious-6d92775ab546969230366b5bddbe51d36f73e7c7.tar.gz
invidious-6d92775ab546969230366b5bddbe51d36f73e7c7.tar.bz2
invidious-6d92775ab546969230366b5bddbe51d36f73e7c7.zip
Add video previews
Diffstat (limited to 'src')
-rw-r--r--src/invidious.cr89
-rw-r--r--src/invidious/videos.cr7
-rw-r--r--src/invidious/views/components/player.ecr4
-rw-r--r--src/invidious/views/components/player_sources.ecr2
-rw-r--r--src/invidious/views/licenses.ecr14
5 files changed, 112 insertions, 4 deletions
diff --git a/src/invidious.cr b/src/invidious.cr
index 1d2e63b2..1399c124 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -3053,6 +3053,86 @@ get "/api/v1/stats" do |env|
statistics.to_json
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|
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>"
end
- webvtt = webvtt + <<-END_CUE
+ webvtt += <<-END_CUE
#{start_time} --> #{end_time}
#{text}
@@ -5054,6 +5134,13 @@ get "/ggpht/*" do |env|
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|
id = env.params.url["id"]
storyboard = env.params.url["storyboard"]
diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr
index 755ee4d7..9a199fad 100644
--- a/src/invidious/videos.cr
+++ b/src/invidious/videos.cr
@@ -281,7 +281,7 @@ struct Video
generate_thumbnails(json, self.id, config, kemal_config)
end
json.field "storyboards" do
- generate_storyboards(json, self.storyboards, config, kemal_config)
+ generate_storyboards(json, self.id, self.storyboards, config, kemal_config)
end
description_html, description = html_to_content(self.description)
@@ -1348,11 +1348,12 @@ def generate_thumbnails(json, id, config, kemal_config)
end
end
-def generate_storyboards(json, storyboards, config, kemal_config)
+def generate_storyboards(json, id, storyboards, config, kemal_config)
json.array do
storyboards.each do |storyboard|
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 "height", storyboard[:height]
json.field "count", storyboard[:count]
diff --git a/src/invidious/views/components/player.ecr b/src/invidious/views/components/player.ecr
index 6ad70033..3afa2af8 100644
--- a/src/invidious/views/components/player.ecr
+++ b/src/invidious/views/components/player.ecr
@@ -217,6 +217,10 @@ if (bpb) {
player.httpSourceSelector();
<% end %>
+player.vttThumbnails({
+ src: 'api/v1/storyboards/<%= video.id %>?height=90'
+});
+
<% if !params.listen && params.annotations %>
var video_container = document.getElementById('player');
let xhr = new XMLHttpRequest();
diff --git a/src/invidious/views/components/player_sources.ecr b/src/invidious/views/components/player_sources.ecr
index f446248e..2fbd41b0 100644
--- a/src/invidious/views/components/player_sources.ecr
+++ b/src/invidious/views/components/player_sources.ecr
@@ -2,12 +2,14 @@
<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-share.css">
+<link rel="stylesheet" href="/css/videojs-vtt-thumbnails.css">
<script src="/js/video.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.hotkeys.min.js"></script>
<script src="/js/videojs-markers.min.js"></script>
<script src="/js/videojs-share.min.js"></script>
+<script src="/js/videojs-vtt-thumbnails.min.js"></script>
<% if params.annotations %>
<link rel="stylesheet" href="/css/videojs-youtube-annotations.min.css">
diff --git a/src/invidious/views/licenses.ecr b/src/invidious/views/licenses.ecr
index bab7762a..8561dee9 100644
--- a/src/invidious/views/licenses.ecr
+++ b/src/invidious/views/licenses.ecr
@@ -95,6 +95,20 @@
<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>
+ <td>
<a href="/js/videojs-youtube-annotations.min.js">videojs-youtube-annotations.min.js</a>
</td>