summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSamantaz Fox <coding@samantaz.fr>2024-02-12 22:10:16 +0100
committerSamantaz Fox <coding@samantaz.fr>2024-02-12 22:10:16 +0100
commitdcbe52c9fb3225190ad5ce26731a51a4c2414c5c (patch)
treeea1bf64b25d32175b92763a4b0da6f06b35d9452 /src
parentbd5df3af5f230ee3e62a894f1944932ff799df90 (diff)
parent7da4a7f72b0e328f72aff884605a21c4ffe7cb04 (diff)
downloadinvidious-dcbe52c9fb3225190ad5ce26731a51a4c2414c5c.tar.gz
invidious-dcbe52c9fb3225190ad5ce26731a51a4c2414c5c.tar.bz2
invidious-dcbe52c9fb3225190ad5ce26731a51a4c2414c5c.zip
Videos: Use start time and end time for clips (#4264)
This PR parses the start and end time for clips. It also adds a new, dedicated API endpoint (`/api/v1/clips/{id}`) for retrieving the start and end time of a clip. Here is a sample response from that new endpoint (`video` is a video object, as described in https://docs.invidious.io/api/common_types/#videoobject): GET `/api/v1/clips/UgkxxPM3BRphCAPLP88YoUGuj79KXPfpNNO_?pretty=1` Response: ``` { "startTime": 8842.645, "endTime": 8855.856, "clipTitle": "✂️ Kirby is pink!", "video": {} } ``` Closes issue 3921
Diffstat (limited to 'src')
-rw-r--r--src/invidious/routes/api/v1/videos.cr43
-rw-r--r--src/invidious/routes/watch.cr6
-rw-r--r--src/invidious/routing.cr1
-rw-r--r--src/invidious/videos/clip.cr22
4 files changed, 72 insertions, 0 deletions
diff --git a/src/invidious/routes/api/v1/videos.cr b/src/invidious/routes/api/v1/videos.cr
index 1017ac9d..9281f4dd 100644
--- a/src/invidious/routes/api/v1/videos.cr
+++ b/src/invidious/routes/api/v1/videos.cr
@@ -363,4 +363,47 @@ module Invidious::Routes::API::V1::Videos
end
end
end
+
+ def self.clips(env)
+ locale = env.get("preferences").as(Preferences).locale
+
+ env.response.content_type = "application/json"
+
+ clip_id = env.params.url["id"]
+ region = env.params.query["region"]?
+ proxy = {"1", "true"}.any? &.== env.params.query["local"]?
+
+ response = YoutubeAPI.resolve_url("https://www.youtube.com/clip/#{clip_id}")
+ return error_json(400, "Invalid clip ID") if response["error"]?
+
+ video_id = response.dig?("endpoint", "watchEndpoint", "videoId").try &.as_s
+ return error_json(400, "Invalid clip ID") if video_id.nil?
+
+ start_time = nil
+ end_time = nil
+ clip_title = nil
+
+ if params = response.dig?("endpoint", "watchEndpoint", "params").try &.as_s
+ start_time, end_time, clip_title = parse_clip_parameters(params)
+ end
+
+ begin
+ video = get_video(video_id, region: region)
+ rescue ex : NotFoundException
+ return error_json(404, ex)
+ rescue ex
+ return error_json(500, ex)
+ end
+
+ return JSON.build do |json|
+ json.object do
+ json.field "startTime", start_time
+ json.field "endTime", end_time
+ json.field "clipTitle", clip_title
+ json.field "video" do
+ Invidious::JSONify::APIv1.video(video, json, locale: locale, proxy: proxy)
+ end
+ end
+ end
+ end
end
diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr
index 3d935f0a..aabe8dfc 100644
--- a/src/invidious/routes/watch.cr
+++ b/src/invidious/routes/watch.cr
@@ -275,6 +275,12 @@ module Invidious::Routes::Watch
return error_template(400, "Invalid clip ID") if response["error"]?
if video_id = response.dig?("endpoint", "watchEndpoint", "videoId")
+ if params = response.dig?("endpoint", "watchEndpoint", "params").try &.as_s
+ start_time, end_time, _ = parse_clip_parameters(params)
+ env.params.query["start"] = start_time.to_s if start_time != nil
+ env.params.query["end"] = end_time.to_s if end_time != nil
+ end
+
return env.redirect "/watch?v=#{video_id}&#{env.params.query}"
else
return error_template(404, "The requested clip doesn't exist")
diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr
index d6bd991c..ba05da19 100644
--- a/src/invidious/routing.cr
+++ b/src/invidious/routing.cr
@@ -235,6 +235,7 @@ module Invidious::Routing
get "/api/v1/captions/:id", {{namespace}}::Videos, :captions
get "/api/v1/annotations/:id", {{namespace}}::Videos, :annotations
get "/api/v1/comments/:id", {{namespace}}::Videos, :comments
+ get "/api/v1/clips/:id", {{namespace}}::Videos, :clips
# Feeds
get "/api/v1/trending", {{namespace}}::Feeds, :trending
diff --git a/src/invidious/videos/clip.cr b/src/invidious/videos/clip.cr
new file mode 100644
index 00000000..29c57182
--- /dev/null
+++ b/src/invidious/videos/clip.cr
@@ -0,0 +1,22 @@
+require "json"
+
+# returns start_time, end_time and clip_title
+def parse_clip_parameters(params) : {Float64?, Float64?, String?}
+ decoded_protobuf = params.try { |i| URI.decode_www_form(i) }
+ .try { |i| Base64.decode(i) }
+ .try { |i| IO::Memory.new(i) }
+ .try { |i| Protodec::Any.parse(i) }
+
+ start_time = decoded_protobuf
+ .try(&.["50:0:embedded"]["2:1:varint"].as_i64)
+ .try { |i| i/1000 }
+
+ end_time = decoded_protobuf
+ .try(&.["50:0:embedded"]["3:2:varint"].as_i64)
+ .try { |i| i/1000 }
+
+ clip_title = decoded_protobuf
+ .try(&.["50:0:embedded"]["4:3:string"].as_s)
+
+ return start_time, end_time, clip_title
+end