mirror of
https://gitea.invidious.io/iv-org/invidious.git
synced 2024-08-15 00:53:41 +00:00
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
This commit is contained in:
commit
dcbe52c9fb
4 changed files with 72 additions and 0 deletions
|
@ -363,4 +363,47 @@ module Invidious::Routes::API::V1::Videos
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -275,6 +275,12 @@ module Invidious::Routes::Watch
|
||||||
return error_template(400, "Invalid clip ID") if response["error"]?
|
return error_template(400, "Invalid clip ID") if response["error"]?
|
||||||
|
|
||||||
if video_id = response.dig?("endpoint", "watchEndpoint", "videoId")
|
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}"
|
return env.redirect "/watch?v=#{video_id}&#{env.params.query}"
|
||||||
else
|
else
|
||||||
return error_template(404, "The requested clip doesn't exist")
|
return error_template(404, "The requested clip doesn't exist")
|
||||||
|
|
|
@ -235,6 +235,7 @@ module Invidious::Routing
|
||||||
get "/api/v1/captions/:id", {{namespace}}::Videos, :captions
|
get "/api/v1/captions/:id", {{namespace}}::Videos, :captions
|
||||||
get "/api/v1/annotations/:id", {{namespace}}::Videos, :annotations
|
get "/api/v1/annotations/:id", {{namespace}}::Videos, :annotations
|
||||||
get "/api/v1/comments/:id", {{namespace}}::Videos, :comments
|
get "/api/v1/comments/:id", {{namespace}}::Videos, :comments
|
||||||
|
get "/api/v1/clips/:id", {{namespace}}::Videos, :clips
|
||||||
|
|
||||||
# Feeds
|
# Feeds
|
||||||
get "/api/v1/trending", {{namespace}}::Feeds, :trending
|
get "/api/v1/trending", {{namespace}}::Feeds, :trending
|
||||||
|
|
22
src/invidious/videos/clip.cr
Normal file
22
src/invidious/videos/clip.cr
Normal file
|
@ -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
|
Loading…
Reference in a new issue