mirror of
https://gitea.invidious.io/iv-org/invidious-copy-2022-03-16.git
synced 2024-08-15 00:53:18 +00:00
Add 'to_json' into respective structs
This commit is contained in:
parent
1c9085556c
commit
12b2ab5da8
7 changed files with 307 additions and 451 deletions
324
src/invidious.cr
324
src/invidious.cr
|
@ -3405,31 +3405,10 @@ get "/api/v1/trending" do |env|
|
||||||
videos = JSON.build do |json|
|
videos = JSON.build do |json|
|
||||||
json.array do
|
json.array do
|
||||||
trending.each do |video|
|
trending.each do |video|
|
||||||
json.object do
|
video.to_json(locale, config, Kemal.config, json)
|
||||||
json.field "title", video.title
|
|
||||||
json.field "videoId", video.id
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, video.id, config, Kemal.config)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
json.field "lengthSeconds", video.length_seconds
|
|
||||||
json.field "viewCount", video.views
|
|
||||||
|
|
||||||
json.field "author", video.author
|
|
||||||
json.field "authorId", video.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{video.ucid}"
|
|
||||||
|
|
||||||
json.field "published", video.published.to_unix
|
|
||||||
json.field "publishedText", translate(locale, "`x` ago", recode_date(video.published, locale))
|
|
||||||
json.field "description", video.description
|
|
||||||
json.field "descriptionHtml", video.description_html
|
|
||||||
json.field "liveNow", video.live_now
|
|
||||||
json.field "paid", video.paid
|
|
||||||
json.field "premium", video.premium
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
videos
|
videos
|
||||||
end
|
end
|
||||||
|
@ -3459,9 +3438,12 @@ get "/api/v1/top" do |env|
|
||||||
next error_message
|
next error_message
|
||||||
end
|
end
|
||||||
|
|
||||||
videos = JSON.build do |json|
|
JSON.build do |json|
|
||||||
json.array do
|
json.array do
|
||||||
top_videos.each do |video|
|
top_videos.each do |video|
|
||||||
|
# Top videos have much more information than provided below (adaptiveFormats, etc)
|
||||||
|
# but can be very out of date, so we only provide a subset here
|
||||||
|
|
||||||
json.object do
|
json.object do
|
||||||
json.field "title", video.title
|
json.field "title", video.title
|
||||||
json.field "videoId", video.id
|
json.field "videoId", video.id
|
||||||
|
@ -3487,8 +3469,6 @@ get "/api/v1/top" do |env|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
videos
|
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/api/v1/channels/:ucid" do |env|
|
get "/api/v1/channels/:ucid" do |env|
|
||||||
|
@ -3577,6 +3557,7 @@ get "/api/v1/channels/:ucid" do |env|
|
||||||
end
|
end
|
||||||
|
|
||||||
channel_info = JSON.build do |json|
|
channel_info = JSON.build do |json|
|
||||||
|
# TODO: Refactor into `to_json` for InvidiousChannel
|
||||||
json.object do
|
json.object do
|
||||||
json.field "author", author
|
json.field "author", author
|
||||||
json.field "authorId", ucid
|
json.field "authorId", ucid
|
||||||
|
@ -3634,35 +3615,7 @@ get "/api/v1/channels/:ucid" do |env|
|
||||||
json.field "latestVideos" do
|
json.field "latestVideos" do
|
||||||
json.array do
|
json.array do
|
||||||
videos.each do |video|
|
videos.each do |video|
|
||||||
json.object do
|
video.to_json(locale, config, Kemal.config, json)
|
||||||
json.field "title", video.title
|
|
||||||
json.field "videoId", video.id
|
|
||||||
|
|
||||||
if auto_generated
|
|
||||||
json.field "author", video.author
|
|
||||||
json.field "authorId", video.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{video.ucid}"
|
|
||||||
else
|
|
||||||
json.field "author", author
|
|
||||||
json.field "authorId", ucid
|
|
||||||
json.field "authorUrl", "/channel/#{ucid}"
|
|
||||||
end
|
|
||||||
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, video.id, config, Kemal.config)
|
|
||||||
end
|
|
||||||
|
|
||||||
json.field "description", video.description
|
|
||||||
json.field "descriptionHtml", video.description_html
|
|
||||||
|
|
||||||
json.field "viewCount", video.views
|
|
||||||
json.field "published", video.published.to_unix
|
|
||||||
json.field "publishedText", translate(locale, "`x` ago", recode_date(video.published, locale))
|
|
||||||
json.field "lengthSeconds", video.length_seconds
|
|
||||||
json.field "liveNow", video.live_now
|
|
||||||
json.field "paid", video.paid
|
|
||||||
json.field "premium", video.premium
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3727,45 +3680,15 @@ end
|
||||||
next error_message
|
next error_message
|
||||||
end
|
end
|
||||||
|
|
||||||
result = JSON.build do |json|
|
JSON.build do |json|
|
||||||
json.array do
|
json.array do
|
||||||
videos.each do |video|
|
videos.each do |video|
|
||||||
json.object do
|
video.to_json(locale, config, Kemal.config, json)
|
||||||
json.field "title", video.title
|
|
||||||
json.field "videoId", video.id
|
|
||||||
|
|
||||||
if auto_generated
|
|
||||||
json.field "author", video.author
|
|
||||||
json.field "authorId", video.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{video.ucid}"
|
|
||||||
else
|
|
||||||
json.field "author", author
|
|
||||||
json.field "authorId", ucid
|
|
||||||
json.field "authorUrl", "/channel/#{ucid}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, video.id, config, Kemal.config)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
json.field "description", video.description
|
|
||||||
json.field "descriptionHtml", video.description_html
|
|
||||||
|
|
||||||
json.field "viewCount", video.views
|
|
||||||
json.field "published", video.published.to_unix
|
|
||||||
json.field "publishedText", translate(locale, "`x` ago", recode_date(video.published, locale))
|
|
||||||
json.field "lengthSeconds", video.length_seconds
|
|
||||||
json.field "liveNow", video.live_now
|
|
||||||
json.field "paid", video.paid
|
|
||||||
json.field "premium", video.premium
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
result
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
{"/api/v1/channels/:ucid/latest", "/api/v1/channels/latest/:ucid"}.each do |route|
|
{"/api/v1/channels/:ucid/latest", "/api/v1/channels/latest/:ucid"}.each do |route|
|
||||||
get route do |env|
|
get route do |env|
|
||||||
|
@ -3786,33 +3709,12 @@ end
|
||||||
JSON.build do |json|
|
JSON.build do |json|
|
||||||
json.array do
|
json.array do
|
||||||
videos.each do |video|
|
videos.each do |video|
|
||||||
json.object do
|
video.to_json(locale, config, Kemal.config, json)
|
||||||
json.field "title", video.title
|
|
||||||
json.field "videoId", video.id
|
|
||||||
|
|
||||||
json.field "authorId", ucid
|
|
||||||
json.field "authorUrl", "/channel/#{ucid}"
|
|
||||||
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, video.id, config, Kemal.config)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
json.field "description", video.description
|
|
||||||
json.field "descriptionHtml", video.description_html
|
|
||||||
|
|
||||||
json.field "viewCount", video.views
|
|
||||||
json.field "published", video.published.to_unix
|
|
||||||
json.field "publishedText", translate(locale, "`x` ago", recode_date(video.published, locale))
|
|
||||||
json.field "lengthSeconds", video.length_seconds
|
|
||||||
json.field "liveNow", video.live_now
|
|
||||||
json.field "paid", video.paid
|
|
||||||
json.field "premium", video.premium
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
{"/api/v1/channels/:ucid/playlists", "/api/v1/channels/playlists/:ucid"}.each do |route|
|
{"/api/v1/channels/:ucid/playlists", "/api/v1/channels/playlists/:ucid"}.each do |route|
|
||||||
get route do |env|
|
get route do |env|
|
||||||
|
@ -3841,32 +3743,8 @@ end
|
||||||
json.field "playlists" do
|
json.field "playlists" do
|
||||||
json.array do
|
json.array do
|
||||||
items.each do |item|
|
items.each do |item|
|
||||||
json.object do
|
if item.is_a?(SearchPlaylist)
|
||||||
if item.is_a?(SearchPlaylist)
|
item.to_json(locale, config, Kemal.config, json)
|
||||||
json.field "title", item.title
|
|
||||||
json.field "playlistId", item.id
|
|
||||||
|
|
||||||
json.field "author", item.author
|
|
||||||
json.field "authorId", item.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{item.ucid}"
|
|
||||||
|
|
||||||
json.field "videoCount", item.video_count
|
|
||||||
json.field "videos" do
|
|
||||||
json.array do
|
|
||||||
item.videos.each do |video|
|
|
||||||
json.object do
|
|
||||||
json.field "title", video.title
|
|
||||||
json.field "videoId", video.id
|
|
||||||
json.field "lengthSeconds", video.length_seconds
|
|
||||||
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, video.id, config, Kemal.config)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3894,90 +3772,13 @@ get "/api/v1/channels/search/:ucid" do |env|
|
||||||
page ||= 1
|
page ||= 1
|
||||||
|
|
||||||
count, search_results = channel_search(query, page, ucid)
|
count, search_results = channel_search(query, page, ucid)
|
||||||
response = JSON.build do |json|
|
JSON.build do |json|
|
||||||
json.array do
|
json.array do
|
||||||
search_results.each do |item|
|
search_results.each do |item|
|
||||||
json.object do
|
item.to_json(locale, config, Kemal.config, json)
|
||||||
case item
|
|
||||||
when SearchVideo
|
|
||||||
json.field "type", "video"
|
|
||||||
json.field "title", item.title
|
|
||||||
json.field "videoId", item.id
|
|
||||||
|
|
||||||
json.field "author", item.author
|
|
||||||
json.field "authorId", item.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{item.ucid}"
|
|
||||||
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, item.id, config, Kemal.config)
|
|
||||||
end
|
|
||||||
|
|
||||||
json.field "description", item.description
|
|
||||||
json.field "descriptionHtml", item.description_html
|
|
||||||
|
|
||||||
json.field "viewCount", item.views
|
|
||||||
json.field "published", item.published.to_unix
|
|
||||||
json.field "publishedText", translate(locale, "`x` ago", recode_date(item.published, locale))
|
|
||||||
json.field "lengthSeconds", item.length_seconds
|
|
||||||
json.field "liveNow", item.live_now
|
|
||||||
json.field "paid", item.paid
|
|
||||||
json.field "premium", item.premium
|
|
||||||
when SearchPlaylist
|
|
||||||
json.field "type", "playlist"
|
|
||||||
json.field "title", item.title
|
|
||||||
json.field "playlistId", item.id
|
|
||||||
|
|
||||||
json.field "author", item.author
|
|
||||||
json.field "authorId", item.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{item.ucid}"
|
|
||||||
|
|
||||||
json.field "videoCount", item.video_count
|
|
||||||
json.field "videos" do
|
|
||||||
json.array do
|
|
||||||
item.videos.each do |video|
|
|
||||||
json.object do
|
|
||||||
json.field "title", video.title
|
|
||||||
json.field "videoId", video.id
|
|
||||||
json.field "lengthSeconds", video.length_seconds
|
|
||||||
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, video.id, config, Kemal.config)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
when SearchChannel
|
|
||||||
json.field "type", "channel"
|
|
||||||
json.field "author", item.author
|
|
||||||
json.field "authorId", item.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{item.ucid}"
|
|
||||||
|
|
||||||
json.field "authorThumbnails" do
|
|
||||||
json.array do
|
|
||||||
qualities = {32, 48, 76, 100, 176, 512}
|
|
||||||
|
|
||||||
qualities.each do |quality|
|
|
||||||
json.object do
|
|
||||||
json.field "url", item.author_thumbnail.gsub("=s176-", "=s#{quality}-")
|
|
||||||
json.field "width", quality
|
|
||||||
json.field "height", quality
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
json.field "subCount", item.subscriber_count
|
|
||||||
json.field "videoCount", item.video_count
|
|
||||||
json.field "description", item.description
|
|
||||||
json.field "descriptionHtml", item.description_html
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
response
|
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/api/v1/search" do |env|
|
get "/api/v1/search" do |env|
|
||||||
|
@ -4019,90 +3820,13 @@ get "/api/v1/search" do |env|
|
||||||
end
|
end
|
||||||
|
|
||||||
count, search_results = search(query, page, search_params, proxies, region).as(Tuple)
|
count, search_results = search(query, page, search_params, proxies, region).as(Tuple)
|
||||||
response = JSON.build do |json|
|
JSON.build do |json|
|
||||||
json.array do
|
json.array do
|
||||||
search_results.each do |item|
|
search_results.each do |item|
|
||||||
json.object do
|
item.to_json(locale, config, Kemal.config, json)
|
||||||
case item
|
|
||||||
when SearchVideo
|
|
||||||
json.field "type", "video"
|
|
||||||
json.field "title", item.title
|
|
||||||
json.field "videoId", item.id
|
|
||||||
|
|
||||||
json.field "author", item.author
|
|
||||||
json.field "authorId", item.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{item.ucid}"
|
|
||||||
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, item.id, config, Kemal.config)
|
|
||||||
end
|
|
||||||
|
|
||||||
json.field "description", item.description
|
|
||||||
json.field "descriptionHtml", item.description_html
|
|
||||||
|
|
||||||
json.field "viewCount", item.views
|
|
||||||
json.field "published", item.published.to_unix
|
|
||||||
json.field "publishedText", translate(locale, "`x` ago", recode_date(item.published, locale))
|
|
||||||
json.field "lengthSeconds", item.length_seconds
|
|
||||||
json.field "liveNow", item.live_now
|
|
||||||
json.field "paid", item.paid
|
|
||||||
json.field "premium", item.premium
|
|
||||||
when SearchPlaylist
|
|
||||||
json.field "type", "playlist"
|
|
||||||
json.field "title", item.title
|
|
||||||
json.field "playlistId", item.id
|
|
||||||
|
|
||||||
json.field "author", item.author
|
|
||||||
json.field "authorId", item.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{item.ucid}"
|
|
||||||
|
|
||||||
json.field "videoCount", item.video_count
|
|
||||||
json.field "videos" do
|
|
||||||
json.array do
|
|
||||||
item.videos.each do |video|
|
|
||||||
json.object do
|
|
||||||
json.field "title", video.title
|
|
||||||
json.field "videoId", video.id
|
|
||||||
json.field "lengthSeconds", video.length_seconds
|
|
||||||
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, video.id, config, Kemal.config)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
when SearchChannel
|
|
||||||
json.field "type", "channel"
|
|
||||||
json.field "author", item.author
|
|
||||||
json.field "authorId", item.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{item.ucid}"
|
|
||||||
|
|
||||||
json.field "authorThumbnails" do
|
|
||||||
json.array do
|
|
||||||
qualities = {32, 48, 76, 100, 176, 512}
|
|
||||||
|
|
||||||
qualities.each do |quality|
|
|
||||||
json.object do
|
|
||||||
json.field "url", item.author_thumbnail.gsub("=s176-", "=s#{quality}-")
|
|
||||||
json.field "width", quality
|
|
||||||
json.field "height", quality
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
json.field "subCount", item.subscriber_count
|
|
||||||
json.field "videoCount", item.video_count
|
|
||||||
json.field "description", item.description
|
|
||||||
json.field "descriptionHtml", item.description_html
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
response
|
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/api/v1/playlists/:plid" do |env|
|
get "/api/v1/playlists/:plid" do |env|
|
||||||
|
@ -4170,26 +3894,12 @@ get "/api/v1/playlists/:plid" do |env|
|
||||||
json.field "videos" do
|
json.field "videos" do
|
||||||
json.array do
|
json.array do
|
||||||
videos.each do |video|
|
videos.each do |video|
|
||||||
json.object do
|
video.to_json(locale, config, Kemal.config, json)
|
||||||
json.field "title", video.title
|
|
||||||
json.field "videoId", video.id
|
|
||||||
|
|
||||||
json.field "author", video.author
|
|
||||||
json.field "authorId", video.ucid
|
|
||||||
json.field "authorUrl", "/channel/#{video.ucid}"
|
|
||||||
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, video.id, config, Kemal.config)
|
|
||||||
end
|
|
||||||
|
|
||||||
json.field "index", video.index
|
|
||||||
json.field "lengthSeconds", video.length_seconds
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if format == "html"
|
if format == "html"
|
||||||
response = JSON.parse(response)
|
response = JSON.parse(response)
|
||||||
|
|
|
@ -135,9 +135,7 @@ def get_batch_channels(channels, db, refresh = false, pull_all_videos = true, ma
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_channel(id, db, refresh = true, pull_all_videos = true)
|
def get_channel(id, db, refresh = true, pull_all_videos = true)
|
||||||
if db.query_one?("SELECT EXISTS (SELECT true FROM channels WHERE id = $1)", id, as: Bool)
|
if channel = db.query_one?("SELECT * FROM channels WHERE id = $1", id, as: InvidiousChannel)
|
||||||
channel = db.query_one("SELECT * FROM channels WHERE id = $1", id, as: InvidiousChannel)
|
|
||||||
|
|
||||||
if refresh && Time.utc - channel.updated > 10.minutes
|
if refresh && Time.utc - channel.updated > 10.minutes
|
||||||
channel = fetch_channel(id, db, pull_all_videos: pull_all_videos)
|
channel = fetch_channel(id, db, pull_all_videos: pull_all_videos)
|
||||||
channel_array = channel.to_a
|
channel_array = channel.to_a
|
||||||
|
|
|
@ -6,7 +6,7 @@ struct MixVideo
|
||||||
ucid: String,
|
ucid: String,
|
||||||
length_seconds: Int32,
|
length_seconds: Int32,
|
||||||
index: Int32,
|
index: Int32,
|
||||||
mixes: Array(String),
|
rdid: String,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ def fetch_mix(rdid, video_id, cookies = nil, locale = nil)
|
||||||
ucid,
|
ucid,
|
||||||
length_seconds,
|
length_seconds,
|
||||||
index,
|
index,
|
||||||
[rdid]
|
rdid
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,32 @@
|
||||||
struct PlaylistVideo
|
struct PlaylistVideo
|
||||||
|
def to_json(locale, config, kemal_config, json : JSON::Builder)
|
||||||
|
json.object do
|
||||||
|
json.field "title", self.title
|
||||||
|
json.field "videoId", self.id
|
||||||
|
|
||||||
|
json.field "author", self.author
|
||||||
|
json.field "authorId", self.ucid
|
||||||
|
json.field "authorUrl", "/channel/#{self.ucid}"
|
||||||
|
|
||||||
|
json.field "videoThumbnails" do
|
||||||
|
generate_thumbnails(json, self.id, config, kemal_config)
|
||||||
|
end
|
||||||
|
|
||||||
|
json.field "index", self.index
|
||||||
|
json.field "lengthSeconds", self.length_seconds
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(locale, config, kemal_config, json : JSON::Builder | Nil = nil)
|
||||||
|
if json
|
||||||
|
to_json(locale, config, kemal_config, json)
|
||||||
|
else
|
||||||
|
JSON.build do |json|
|
||||||
|
to_json(locale, config, kemal_config, json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
db_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
|
|
|
@ -50,6 +50,43 @@ struct SearchVideo
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_json(locale, config, kemal_config, json : JSON::Builder)
|
||||||
|
json.object do
|
||||||
|
json.field "type", "video"
|
||||||
|
json.field "title", self.title
|
||||||
|
json.field "videoId", self.id
|
||||||
|
|
||||||
|
json.field "author", self.author
|
||||||
|
json.field "authorId", self.ucid
|
||||||
|
json.field "authorUrl", "/channel/#{self.ucid}"
|
||||||
|
|
||||||
|
json.field "videoThumbnails" do
|
||||||
|
generate_thumbnails(json, self.id, config, kemal_config)
|
||||||
|
end
|
||||||
|
|
||||||
|
json.field "description", self.description
|
||||||
|
json.field "descriptionHtml", self.description_html
|
||||||
|
|
||||||
|
json.field "viewCount", self.views
|
||||||
|
json.field "published", self.published.to_unix
|
||||||
|
json.field "publishedText", translate(locale, "`x` ago", recode_date(self.published, locale))
|
||||||
|
json.field "lengthSeconds", self.length_seconds
|
||||||
|
json.field "liveNow", self.live_now
|
||||||
|
json.field "paid", self.paid
|
||||||
|
json.field "premium", self.premium
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(locale, config, kemal_config, json : JSON::Builder | Nil = nil)
|
||||||
|
if json
|
||||||
|
to_json(locale, config, kemal_config, json)
|
||||||
|
else
|
||||||
|
JSON.build do |json|
|
||||||
|
to_json(locale, config, kemal_config, json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
db_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
|
@ -76,6 +113,45 @@ struct SearchPlaylistVideo
|
||||||
end
|
end
|
||||||
|
|
||||||
struct SearchPlaylist
|
struct SearchPlaylist
|
||||||
|
def to_json(locale, config, kemal_config, json : JSON::Builder)
|
||||||
|
json.object do
|
||||||
|
json.field "type", "playlist"
|
||||||
|
json.field "title", self.title
|
||||||
|
json.field "playlistId", self.id
|
||||||
|
|
||||||
|
json.field "author", self.author
|
||||||
|
json.field "authorId", self.ucid
|
||||||
|
json.field "authorUrl", "/channel/#{self.ucid}"
|
||||||
|
|
||||||
|
json.field "videoCount", self.video_count
|
||||||
|
json.field "videos" do
|
||||||
|
json.array do
|
||||||
|
self.videos.each do |video|
|
||||||
|
json.object do
|
||||||
|
json.field "title", video.title
|
||||||
|
json.field "videoId", video.id
|
||||||
|
json.field "lengthSeconds", video.length_seconds
|
||||||
|
|
||||||
|
json.field "videoThumbnails" do
|
||||||
|
generate_thumbnails(json, video.id, config, Kemal.config)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(locale, config, kemal_config, json : JSON::Builder | Nil = nil)
|
||||||
|
if json
|
||||||
|
to_json(locale, config, kemal_config, json)
|
||||||
|
else
|
||||||
|
JSON.build do |json|
|
||||||
|
to_json(locale, config, kemal_config, json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
db_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
|
@ -88,6 +164,44 @@ struct SearchPlaylist
|
||||||
end
|
end
|
||||||
|
|
||||||
struct SearchChannel
|
struct SearchChannel
|
||||||
|
def to_json(locale, config, kemal_config, json : JSON::Builder)
|
||||||
|
json.object do
|
||||||
|
json.field "type", "channel"
|
||||||
|
json.field "author", self.author
|
||||||
|
json.field "authorId", self.ucid
|
||||||
|
json.field "authorUrl", "/channel/#{self.ucid}"
|
||||||
|
|
||||||
|
json.field "authorThumbnails" do
|
||||||
|
json.array do
|
||||||
|
qualities = {32, 48, 76, 100, 176, 512}
|
||||||
|
|
||||||
|
qualities.each do |quality|
|
||||||
|
json.object do
|
||||||
|
json.field "url", self.author_thumbnail.gsub("=s176-", "=s#{quality}-")
|
||||||
|
json.field "width", quality
|
||||||
|
json.field "height", quality
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
json.field "subCount", self.subscriber_count
|
||||||
|
json.field "videoCount", self.video_count
|
||||||
|
json.field "description", self.description
|
||||||
|
json.field "descriptionHtml", self.description_html
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json(locale, config, kemal_config, json : JSON::Builder | Nil = nil)
|
||||||
|
if json
|
||||||
|
to_json(locale, config, kemal_config, json)
|
||||||
|
else
|
||||||
|
JSON.build do |json|
|
||||||
|
to_json(locale, config, kemal_config, json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
db_mapping({
|
db_mapping({
|
||||||
author: String,
|
author: String,
|
||||||
ucid: String,
|
ucid: String,
|
||||||
|
|
|
@ -273,184 +273,182 @@ struct Video
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_json(locale, config, kemal_config, decrypt_function)
|
def to_json(locale, config, kemal_config, decrypt_function, json : JSON::Builder)
|
||||||
JSON.build do |json|
|
json.object do
|
||||||
json.object do
|
json.field "type", "video"
|
||||||
json.field "type", "video"
|
|
||||||
|
|
||||||
json.field "title", self.title
|
json.field "title", self.title
|
||||||
json.field "videoId", self.id
|
json.field "videoId", self.id
|
||||||
json.field "videoThumbnails" do
|
json.field "videoThumbnails" do
|
||||||
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.id, 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)
|
||||||
|
|
||||||
json.field "description", description
|
json.field "description", description
|
||||||
json.field "descriptionHtml", description_html
|
json.field "descriptionHtml", description_html
|
||||||
json.field "published", self.published.to_unix
|
json.field "published", self.published.to_unix
|
||||||
json.field "publishedText", translate(locale, "`x` ago", recode_date(self.published, locale))
|
json.field "publishedText", translate(locale, "`x` ago", recode_date(self.published, locale))
|
||||||
json.field "keywords", self.keywords
|
json.field "keywords", self.keywords
|
||||||
|
|
||||||
json.field "viewCount", self.views
|
json.field "viewCount", self.views
|
||||||
json.field "likeCount", self.likes
|
json.field "likeCount", self.likes
|
||||||
json.field "dislikeCount", self.dislikes
|
json.field "dislikeCount", self.dislikes
|
||||||
|
|
||||||
json.field "paid", self.paid
|
json.field "paid", self.paid
|
||||||
json.field "premium", self.premium
|
json.field "premium", self.premium
|
||||||
json.field "isFamilyFriendly", self.is_family_friendly
|
json.field "isFamilyFriendly", self.is_family_friendly
|
||||||
json.field "allowedRegions", self.allowed_regions
|
json.field "allowedRegions", self.allowed_regions
|
||||||
json.field "genre", self.genre
|
json.field "genre", self.genre
|
||||||
json.field "genreUrl", self.genre_url
|
json.field "genreUrl", self.genre_url
|
||||||
|
|
||||||
json.field "author", self.author
|
json.field "author", self.author
|
||||||
json.field "authorId", self.ucid
|
json.field "authorId", self.ucid
|
||||||
json.field "authorUrl", "/channel/#{self.ucid}"
|
json.field "authorUrl", "/channel/#{self.ucid}"
|
||||||
|
|
||||||
json.field "authorThumbnails" do
|
json.field "authorThumbnails" do
|
||||||
json.array do
|
json.array do
|
||||||
qualities = {32, 48, 76, 100, 176, 512}
|
qualities = {32, 48, 76, 100, 176, 512}
|
||||||
|
|
||||||
qualities.each do |quality|
|
qualities.each do |quality|
|
||||||
json.object do
|
json.object do
|
||||||
json.field "url", self.author_thumbnail.gsub("=s48-", "=s#{quality}-")
|
json.field "url", self.author_thumbnail.gsub("=s48-", "=s#{quality}-")
|
||||||
json.field "width", quality
|
json.field "width", quality
|
||||||
json.field "height", quality
|
json.field "height", quality
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
json.field "subCountText", self.sub_count_text
|
json.field "subCountText", self.sub_count_text
|
||||||
|
|
||||||
json.field "lengthSeconds", self.info["length_seconds"].to_i
|
json.field "lengthSeconds", self.info["length_seconds"].to_i
|
||||||
json.field "allowRatings", self.allow_ratings
|
json.field "allowRatings", self.allow_ratings
|
||||||
json.field "rating", self.info["avg_rating"].to_f32
|
json.field "rating", self.info["avg_rating"].to_f32
|
||||||
json.field "isListed", self.is_listed
|
json.field "isListed", self.is_listed
|
||||||
json.field "liveNow", self.live_now
|
json.field "liveNow", self.live_now
|
||||||
json.field "isUpcoming", self.is_upcoming
|
json.field "isUpcoming", self.is_upcoming
|
||||||
|
|
||||||
if self.premiere_timestamp
|
if self.premiere_timestamp
|
||||||
json.field "premiereTimestamp", self.premiere_timestamp.not_nil!.to_unix
|
json.field "premiereTimestamp", self.premiere_timestamp.not_nil!.to_unix
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.player_response["streamingData"]?.try &.["hlsManifestUrl"]?
|
if self.player_response["streamingData"]?.try &.["hlsManifestUrl"]?
|
||||||
host_url = make_host_url(config, kemal_config)
|
host_url = make_host_url(config, kemal_config)
|
||||||
|
|
||||||
hlsvp = self.player_response["streamingData"]["hlsManifestUrl"].as_s
|
hlsvp = self.player_response["streamingData"]["hlsManifestUrl"].as_s
|
||||||
hlsvp = hlsvp.gsub("https://manifest.googlevideo.com", host_url)
|
hlsvp = hlsvp.gsub("https://manifest.googlevideo.com", host_url)
|
||||||
|
|
||||||
json.field "hlsUrl", hlsvp
|
json.field "hlsUrl", hlsvp
|
||||||
end
|
end
|
||||||
|
|
||||||
json.field "dashUrl", "#{make_host_url(config, kemal_config)}/api/manifest/dash/id/#{id}"
|
json.field "dashUrl", "#{make_host_url(config, kemal_config)}/api/manifest/dash/id/#{id}"
|
||||||
|
|
||||||
json.field "adaptiveFormats" do
|
json.field "adaptiveFormats" do
|
||||||
json.array do
|
json.array do
|
||||||
self.adaptive_fmts(decrypt_function).each do |fmt|
|
self.adaptive_fmts(decrypt_function).each do |fmt|
|
||||||
json.object do
|
json.object do
|
||||||
json.field "index", fmt["index"]
|
json.field "index", fmt["index"]
|
||||||
json.field "bitrate", fmt["bitrate"]
|
json.field "bitrate", fmt["bitrate"]
|
||||||
json.field "init", fmt["init"]
|
json.field "init", fmt["init"]
|
||||||
json.field "url", fmt["url"]
|
json.field "url", fmt["url"]
|
||||||
json.field "itag", fmt["itag"]
|
json.field "itag", fmt["itag"]
|
||||||
json.field "type", fmt["type"]
|
json.field "type", fmt["type"]
|
||||||
json.field "clen", fmt["clen"]
|
json.field "clen", fmt["clen"]
|
||||||
json.field "lmt", fmt["lmt"]
|
json.field "lmt", fmt["lmt"]
|
||||||
json.field "projectionType", fmt["projection_type"]
|
json.field "projectionType", fmt["projection_type"]
|
||||||
|
|
||||||
fmt_info = itag_to_metadata?(fmt["itag"])
|
fmt_info = itag_to_metadata?(fmt["itag"])
|
||||||
if fmt_info
|
if fmt_info
|
||||||
fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.to_i || 30
|
fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.to_i || 30
|
||||||
json.field "fps", fps
|
json.field "fps", fps
|
||||||
json.field "container", fmt_info["ext"]
|
json.field "container", fmt_info["ext"]
|
||||||
json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"]
|
json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"]
|
||||||
|
|
||||||
if fmt_info["height"]?
|
if fmt_info["height"]?
|
||||||
json.field "resolution", "#{fmt_info["height"]}p"
|
json.field "resolution", "#{fmt_info["height"]}p"
|
||||||
|
|
||||||
quality_label = "#{fmt_info["height"]}p"
|
quality_label = "#{fmt_info["height"]}p"
|
||||||
if fps > 30
|
if fps > 30
|
||||||
quality_label += "60"
|
quality_label += "60"
|
||||||
end
|
end
|
||||||
json.field "qualityLabel", quality_label
|
json.field "qualityLabel", quality_label
|
||||||
|
|
||||||
if fmt_info["width"]?
|
if fmt_info["width"]?
|
||||||
json.field "size", "#{fmt_info["width"]}x#{fmt_info["height"]}"
|
json.field "size", "#{fmt_info["width"]}x#{fmt_info["height"]}"
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
json.field "formatStreams" do
|
json.field "formatStreams" do
|
||||||
json.array do
|
json.array do
|
||||||
self.fmt_stream(decrypt_function).each do |fmt|
|
self.fmt_stream(decrypt_function).each do |fmt|
|
||||||
json.object do
|
json.object do
|
||||||
json.field "url", fmt["url"]
|
json.field "url", fmt["url"]
|
||||||
json.field "itag", fmt["itag"]
|
json.field "itag", fmt["itag"]
|
||||||
json.field "type", fmt["type"]
|
json.field "type", fmt["type"]
|
||||||
json.field "quality", fmt["quality"]
|
json.field "quality", fmt["quality"]
|
||||||
|
|
||||||
fmt_info = itag_to_metadata?(fmt["itag"])
|
fmt_info = itag_to_metadata?(fmt["itag"])
|
||||||
if fmt_info
|
if fmt_info
|
||||||
fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.to_i || 30
|
fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.to_i || 30
|
||||||
json.field "fps", fps
|
json.field "fps", fps
|
||||||
json.field "container", fmt_info["ext"]
|
json.field "container", fmt_info["ext"]
|
||||||
json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"]
|
json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"]
|
||||||
|
|
||||||
if fmt_info["height"]?
|
if fmt_info["height"]?
|
||||||
json.field "resolution", "#{fmt_info["height"]}p"
|
json.field "resolution", "#{fmt_info["height"]}p"
|
||||||
|
|
||||||
quality_label = "#{fmt_info["height"]}p"
|
quality_label = "#{fmt_info["height"]}p"
|
||||||
if fps > 30
|
if fps > 30
|
||||||
quality_label += "60"
|
quality_label += "60"
|
||||||
end
|
end
|
||||||
json.field "qualityLabel", quality_label
|
json.field "qualityLabel", quality_label
|
||||||
|
|
||||||
if fmt_info["width"]?
|
if fmt_info["width"]?
|
||||||
json.field "size", "#{fmt_info["width"]}x#{fmt_info["height"]}"
|
json.field "size", "#{fmt_info["width"]}x#{fmt_info["height"]}"
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
json.field "captions" do
|
json.field "captions" do
|
||||||
json.array do
|
json.array do
|
||||||
self.captions.each do |caption|
|
self.captions.each do |caption|
|
||||||
|
json.object do
|
||||||
|
json.field "label", caption.name.simpleText
|
||||||
|
json.field "languageCode", caption.languageCode
|
||||||
|
json.field "url", "/api/v1/captions/#{id}?label=#{URI.escape(caption.name.simpleText)}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
json.field "recommendedVideos" do
|
||||||
|
json.array do
|
||||||
|
self.info["rvs"]?.try &.split(",").each do |rv|
|
||||||
|
rv = HTTP::Params.parse(rv)
|
||||||
|
|
||||||
|
if rv["id"]?
|
||||||
json.object do
|
json.object do
|
||||||
json.field "label", caption.name.simpleText
|
json.field "videoId", rv["id"]
|
||||||
json.field "languageCode", caption.languageCode
|
json.field "title", rv["title"]
|
||||||
json.field "url", "/api/v1/captions/#{id}?label=#{URI.escape(caption.name.simpleText)}"
|
json.field "videoThumbnails" do
|
||||||
end
|
generate_thumbnails(json, rv["id"], config, kemal_config)
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
json.field "recommendedVideos" do
|
|
||||||
json.array do
|
|
||||||
self.info["rvs"]?.try &.split(",").each do |rv|
|
|
||||||
rv = HTTP::Params.parse(rv)
|
|
||||||
|
|
||||||
if rv["id"]?
|
|
||||||
json.object do
|
|
||||||
json.field "videoId", rv["id"]
|
|
||||||
json.field "title", rv["title"]
|
|
||||||
json.field "videoThumbnails" do
|
|
||||||
generate_thumbnails(json, rv["id"], config, kemal_config)
|
|
||||||
end
|
|
||||||
json.field "author", rv["author"]
|
|
||||||
json.field "lengthSeconds", rv["length_seconds"].to_i
|
|
||||||
json.field "viewCountText", rv["short_view_count_text"]
|
|
||||||
end
|
end
|
||||||
|
json.field "author", rv["author"]
|
||||||
|
json.field "lengthSeconds", rv["length_seconds"].to_i
|
||||||
|
json.field "viewCountText", rv["short_view_count_text"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -459,6 +457,16 @@ struct Video
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_json(locale, config, kemal_config, decrypt_function, json : JSON::Builder | Nil = nil)
|
||||||
|
if json
|
||||||
|
to_json(locale, config, kemal_config, decrypt_function, json)
|
||||||
|
else
|
||||||
|
JSON.build do |json|
|
||||||
|
to_json(locale, config, kemal_config, decrypt_function, json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def allow_ratings
|
def allow_ratings
|
||||||
allow_ratings = player_response["videoDetails"]?.try &.["allowRatings"]?.try &.as_bool
|
allow_ratings = player_response["videoDetails"]?.try &.["allowRatings"]?.try &.as_bool
|
||||||
|
|
||||||
|
@ -848,9 +856,7 @@ class VideoRedirect < Exception
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_video(id, db, proxies = {} of String => Array({ip: String, port: Int32}), refresh = true, region = nil, force_refresh = false)
|
def get_video(id, db, proxies = {} of String => Array({ip: String, port: Int32}), refresh = true, region = nil, force_refresh = false)
|
||||||
if db.query_one?("SELECT EXISTS (SELECT true FROM videos WHERE id = $1)", id, as: Bool) && !region
|
if (video = db.query_one?("SELECT * FROM videos WHERE id = $1", id, as: Video)) && !region
|
||||||
video = db.query_one("SELECT * FROM videos WHERE id = $1", id, as: Video)
|
|
||||||
|
|
||||||
# If record was last updated over 10 minutes ago, or video has since premiered,
|
# If record was last updated over 10 minutes ago, or video has since premiered,
|
||||||
# refresh (expire param in response lasts for 6 hours)
|
# refresh (expire param in response lasts for 6 hours)
|
||||||
if (refresh &&
|
if (refresh &&
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
</b>
|
</b>
|
||||||
</p>
|
</p>
|
||||||
<% when MixVideo %>
|
<% when MixVideo %>
|
||||||
<a style="width:100%" href="/watch?v=<%= item.id %>&list=<%= item.mixes[0] %>">
|
<a style="width:100%" href="/watch?v=<%= item.id %>&list=<%= item.rdid %>">
|
||||||
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
||||||
<div class="thumbnail">
|
<div class="thumbnail">
|
||||||
<img class="thumbnail" src="/vi/<%= item.id %>/mqdefault.jpg"/>
|
<img class="thumbnail" src="/vi/<%= item.id %>/mqdefault.jpg"/>
|
||||||
|
|
Loading…
Reference in a new issue