mirror of
https://github.com/iv-org/invidious
synced 2024-11-03 03:40:35 +00:00
Freshen up for the big dance
This commit is contained in:
parent
60c618942f
commit
38cff5a752
@ -1,5 +1,5 @@
|
|||||||
a.link {
|
a.link {
|
||||||
color: #222;
|
color: #333;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
120
src/invidious.cr
120
src/invidious.cr
@ -25,7 +25,7 @@ class Video
|
|||||||
|
|
||||||
module XMLConverter
|
module XMLConverter
|
||||||
def self.from_rs(rs)
|
def self.from_rs(rs)
|
||||||
XML.parse(rs.read(String))
|
XML.parse_html(rs.read(String))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ class Video
|
|||||||
},
|
},
|
||||||
html: {
|
html: {
|
||||||
type: XML::Node,
|
type: XML::Node,
|
||||||
default: XML.parse(""),
|
default: XML.parse_html(""),
|
||||||
converter: Video::XMLConverter,
|
converter: Video::XMLConverter,
|
||||||
},
|
},
|
||||||
updated: Time,
|
updated: Time,
|
||||||
@ -69,20 +69,24 @@ def ci_lower_bound(pos, n)
|
|||||||
return (phat + z*z/(2*n) - z * Math.sqrt((phat*(1 - phat) + z*z/(4*n))/n))/(1 + z*z/n)
|
return (phat + z*z/(2*n) - z * Math.sqrt((phat*(1 - phat) + z*z/(4*n))/n))/(1 + z*z/n)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_video(id)
|
def get_client
|
||||||
# Grab connection from pool
|
|
||||||
while POOL.empty?
|
while POOL.empty?
|
||||||
sleep rand(0..10).milliseconds
|
sleep rand(0..10).milliseconds
|
||||||
end
|
end
|
||||||
|
|
||||||
client = POOL.pop
|
return POOL.pop
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_video(id)
|
||||||
|
# Grab connection from pool
|
||||||
|
client = get_client
|
||||||
|
|
||||||
# client = HTTP::Client.new("www.youtube.com", 443, CONTEXT)
|
# client = HTTP::Client.new("www.youtube.com", 443, CONTEXT)
|
||||||
info = client.get("/get_video_info?video_id=#{id}&el=info&ps=default&eurl=&gl=US&hl=en").body
|
info = client.get("/get_video_info?video_id=#{id}&el=detailpage&ps=default&eurl=&gl=US&hl=en").body
|
||||||
info = HTTP::Params.parse(info)
|
info = HTTP::Params.parse(info)
|
||||||
|
|
||||||
html = client.get("/watch?v=#{id}").body
|
html = client.get("/watch?v=#{id}").body
|
||||||
html = XML.parse(html)
|
html = XML.parse_html(html)
|
||||||
|
|
||||||
if info["reason"]?
|
if info["reason"]?
|
||||||
raise info["reason"]
|
raise info["reason"]
|
||||||
@ -119,6 +123,7 @@ end
|
|||||||
|
|
||||||
get "/watch" do |env|
|
get "/watch" do |env|
|
||||||
id = env.params.query["v"]
|
id = env.params.query["v"]
|
||||||
|
listen = env.params.query["listen"]? || "false"
|
||||||
|
|
||||||
begin
|
begin
|
||||||
video = get_video(id)
|
video = get_video(id)
|
||||||
@ -127,14 +132,7 @@ get "/watch" do |env|
|
|||||||
next templated "error"
|
next templated "error"
|
||||||
end
|
end
|
||||||
|
|
||||||
query = HTTP::Params.parse(env.request.query.not_nil!)
|
player_response = JSON.parse(video.info["player_response"])
|
||||||
if query["listen"]? && query["listen"] == "true"
|
|
||||||
query.delete_all("listen")
|
|
||||||
listen = true
|
|
||||||
else
|
|
||||||
query["listen"] = "true"
|
|
||||||
listen = false
|
|
||||||
end
|
|
||||||
|
|
||||||
fmt_stream = [] of HTTP::Params
|
fmt_stream = [] of HTTP::Params
|
||||||
video.info["url_encoded_fmt_stream_map"].split(",") do |string|
|
video.info["url_encoded_fmt_stream_map"].split(",") do |string|
|
||||||
@ -148,83 +146,65 @@ get "/watch" do |env|
|
|||||||
adaptive_fmts << HTTP::Params.parse(string)
|
adaptive_fmts << HTTP::Params.parse(string)
|
||||||
end
|
end
|
||||||
|
|
||||||
related_videos = video.html.xpath_nodes(%q(//li/div/a[contains(@class,"content-link")]/@href))
|
|
||||||
if related_videos.empty?
|
|
||||||
related_videos = video.html.xpath_nodes(%q(//ytd-compact-video-renderer/div/a/@href))
|
|
||||||
end
|
|
||||||
|
|
||||||
related_videos_list = [] of Video
|
|
||||||
related_videos.each do |related_video|
|
|
||||||
related_id = related_video.content.split("=")[1]
|
|
||||||
begin
|
|
||||||
related_videos_list << get_video(related_id, false)
|
|
||||||
rescue ex
|
|
||||||
p "#{related_id}: #{ex.message}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
likes = video.html.xpath_node(%q(//button[@title="I like this"]/span))
|
likes = video.html.xpath_node(%q(//button[@title="I like this"]/span))
|
||||||
if likes
|
likes = likes ? likes.content.delete(",").to_i : 1
|
||||||
likes = likes.content.delete(",").to_i
|
|
||||||
else
|
|
||||||
likes = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
dislikes = video.html.xpath_node(%q(//button[@title="I dislike this"]/span))
|
dislikes = video.html.xpath_node(%q(//button[@title="I dislike this"]/span))
|
||||||
if dislikes
|
dislikes = dislikes ? dislikes.content.delete(",").to_i : 1
|
||||||
dislikes = dislikes.content.delete(",").to_i
|
|
||||||
else
|
|
||||||
dislikes = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
description = video.html.xpath_node(%q(//p[@id="eow-description"]))
|
description = video.html.xpath_node(%q(//p[@id="eow-description"]))
|
||||||
if description
|
description = description ? description.to_xml : "Could not load description"
|
||||||
description = description.to_xml
|
|
||||||
else
|
|
||||||
description = ""
|
|
||||||
end
|
|
||||||
|
|
||||||
views = video.info["view_count"].to_i64
|
views = video.info["view_count"].to_i64
|
||||||
rating = video.info["avg_rating"].to_f64
|
rating = video.info["avg_rating"].to_f64
|
||||||
|
|
||||||
likes = likes.to_f
|
engagement = ((dislikes.to_f + likes.to_f)/views * 100)
|
||||||
dislikes = dislikes.to_f
|
calculated_rating = (likes.to_f/(likes.to_f + dislikes.to_f) * 4 + 1)
|
||||||
views = views.to_f
|
|
||||||
|
|
||||||
engagement = ((dislikes + likes)/views * 100)
|
rvs = [] of Hash(String, String)
|
||||||
calculated_rating = (likes/(likes + dislikes) * 4 + 1)
|
video.info["rvs"].split(",").each do |rv|
|
||||||
|
rvs << HTTP::Params.parse(rv).to_h
|
||||||
|
end
|
||||||
|
|
||||||
templated "watch"
|
templated "watch"
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/search" do |env|
|
get "/search" do |env|
|
||||||
query = env.params.query["q"]
|
query = env.params.query["q"]
|
||||||
|
page = env.params.query["page"]? && env.params.query["page"].to_i? ? env.params.query["page"].to_i : 1
|
||||||
|
speed = env.params.query["speed"]? && env.params.query["speed"].to_i? ? env.params.query["speed"].to_i : 1
|
||||||
|
|
||||||
while POOL.empty?
|
client = get_client
|
||||||
sleep rand(0..10).milliseconds
|
|
||||||
end
|
|
||||||
|
|
||||||
client = POOL.pop
|
html = client.get("https://www.youtube.com/results?q=#{URI.escape(query)}&page=#{page}").body
|
||||||
|
html = XML.parse_html(html)
|
||||||
|
|
||||||
html = client.get("https://www.youtube.com/results?q=#{URI.escape(query)}&page=1").body
|
videos = Array(Hash(String, String)).new
|
||||||
html = XML.parse(html)
|
|
||||||
|
|
||||||
videos = html.xpath_nodes(%q(//div[contains(@class,"yt-lockup-video")]/div/div[contains(@class,"yt-lockup-thumbnail")]/a/@href))
|
html.xpath_nodes(%q(//div[contains(@class,"yt-lockup-video")]/div)).each do |item|
|
||||||
channels = html.xpath_nodes(%q(//div[contains(@class,"yt-lockup-channel")]/div/div[contains(@class,"yt-lockup-thumbnail")]/a/@href))
|
video = {} of String => String
|
||||||
|
|
||||||
if videos.empty?
|
link = item.xpath_node(%q(div/div[@class="yt-lockup-content"]/h3/a/@href))
|
||||||
videos = html.xpath_nodes(%q(//div[contains(@class,"yt-lockup-video")]/div/div[@class="yt-lockup-content"]/h3/a/@href))
|
if link
|
||||||
channels = html.xpath_nodes(%q(//div[contains(@class,"yt-lockup-channel")]/div[@class="yt-lockup-content"]/h3/a/@href))
|
video["link"] = link.content
|
||||||
end
|
else
|
||||||
|
link = item.xpath_node(%q(div[@class="yt-lockup-content"]/h3/a/@href))
|
||||||
videos_list = [] of Video
|
if link
|
||||||
videos.each do |video|
|
video["link"] = link.content
|
||||||
id = video.content.split("=")[1]
|
end
|
||||||
begin
|
|
||||||
videos_list << get_video(id, false)
|
|
||||||
rescue ex
|
|
||||||
p "#{id}: #{ex.message}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
title = item.xpath_node(%q(div/div[@class="yt-lockup-content"]/h3/a))
|
||||||
|
if title
|
||||||
|
video["title"] = title.content
|
||||||
|
else
|
||||||
|
title = item.xpath_node(%q(div[@class="yt-lockup-content"]/h3/a))
|
||||||
|
if title
|
||||||
|
video["title"] = title.content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
videos << video
|
||||||
end
|
end
|
||||||
|
|
||||||
POOL << client
|
POOL << client
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
<% content_for "header" do %>
|
||||||
|
<% end %>
|
@ -1,17 +1,9 @@
|
|||||||
<% content_for "header" do %>
|
<% content_for "header" do %>
|
||||||
<%= query.size > 30 ? query[0,30] + "... - " : query %>
|
<%= query.size > 30 ? query[0,30].chomp("...") + "... - " : query + " - " %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% videos_list.each do |video| %>
|
|
||||||
<div class="pure-g">
|
<% videos.each do |item| %>
|
||||||
<div class="pure-u-1 pure-u-md-1-6">
|
<p><a class="link" href="<%= item["link"] %>"><%= item["title"] %></a></p>
|
||||||
<a class="link" href="/watch?v=<%= video.id %>">
|
<% end %>
|
||||||
<img style="width: 90%" src="<%= video.info["thumbnail_url"] %>">
|
|
||||||
</a>
|
<p style="text-align: right"><a href="/search?q=<%= query %>&page=<%= page + 1 %>">Next page</a></p>
|
||||||
</div>
|
|
||||||
<div class="pure-u-1 pure-u-md-5-6">
|
|
||||||
<a style="width: 100%; height:100%; display: block; position: relative" class="link" href="/watch?v=<%= video.id %>">
|
|
||||||
<%= video.info["title"] %>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
@ -1,8 +1,9 @@
|
|||||||
<% content_for "header" do %>
|
<% content_for "header" do %>
|
||||||
<%= video.info["title"] + " - " %>
|
<%= video.info["title"] + " - " %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<video style="width: 100%" poster="<%= video.info.has_key?("iurlhq720") ? video.info["iurlhq720"] : video.info["iurlmq"] %>" controls>
|
|
||||||
<% if listen %>
|
<video style="width: 100%" poster="<%= player_response["videoDetails"]["thumbnail"]["thumbnails"][-1]["url"] %>" controls>
|
||||||
|
<% if listen == "true" %>
|
||||||
<% adaptive_fmts.each do |fmt| %>
|
<% adaptive_fmts.each do |fmt| %>
|
||||||
<% url = fmt["url"] %>
|
<% url = fmt["url"] %>
|
||||||
<% type = fmt["type"].to_s.split(";")[0] %>
|
<% type = fmt["type"].to_s.split(";")[0] %>
|
||||||
@ -16,29 +17,43 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</video>
|
</video>
|
||||||
<h1><%= video.info["title"] %> <a class="link" href="/watch?<%= query.to_s %>">
|
<h1>
|
||||||
<i class="fa <%= listen ? "fa-video-camera" : "fa-volume-up" %>" aria-hidden="true"></i>
|
<%= video.info["title"] %>
|
||||||
|
<% if listen == "true" %>
|
||||||
|
<a class="link" href="/watch?v=<%= id %>">
|
||||||
|
<i class="fa fa-video-camera" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<% else %>
|
||||||
|
<a class="link" href="/watch?v=<%= id %>&listen=true">
|
||||||
|
<i class="fa fa-volume-up" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
<% end %>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
<div class="pure-u-1 pure-u-md-1-5">
|
<div class="pure-u-1 pure-u-md-1-5">
|
||||||
<p><i class="fa fa-eye" aria-hidden="true"></i> <%= views.to_i %></p>
|
<p><i class="fa fa-eye" aria-hidden="true"></i> <%= views %></p>
|
||||||
<p><i class="fa fa-thumbs-up" aria-hidden="true"></i> <%= likes.to_i %></p>
|
<p><i class="fa fa-thumbs-up" aria-hidden="true"></i> <%= likes %></p>
|
||||||
<p><i class="fa fa-thumbs-down" aria-hidden="true"></i> <%= dislikes.to_i %></p>
|
<p><i class="fa fa-thumbs-down" aria-hidden="true"></i> <%= dislikes %></p>
|
||||||
<p>Wilson Score : <%= ci_lower_bound(likes, likes + dislikes).round(4) %></p>
|
<p id="Wilson">Wilson Score : <%= ci_lower_bound(likes, likes + dislikes).round(4) %></p>
|
||||||
<p>Rating : <%= rating.round(4) %> / 5</p>
|
<p id="Rating">Rating : <%= rating.round(4) %> / 5</p>
|
||||||
<p>Engagement : <%= engagement.round(2) %>%</p>
|
<p id="Engagement">Engagement : <%= engagement.round(2) %>%</p>
|
||||||
<p>Earnings : <%= video.info.has_key?("allowed_ads") ? "~$" + ((views.to_f / 500).round(2)).to_s : "Unmonetized" %></p>
|
|
||||||
<p>Allowed ads : <br><%= video.info.has_key?("allowed_ads") ? video.info["allowed_ads"] : "Unmonetized" %></p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-1 pure-u-md-3-5">
|
<div class="pure-u-1 pure-u-md-3-5">
|
||||||
<p><a class="link" href="https://youtube.com/channel/<%= video.info["ucid"] %>"><%= video.info["author"] %></a></p>
|
<p><a class="link" href="https://youtube.com/channel/<%= video.info["ucid"] %>"><%= video.info["author"] %></a></p>
|
||||||
<p><%= description %></p>
|
<p id="Description"><%= description %></p>
|
||||||
|
<% rvs.each do |rv| %>
|
||||||
|
<% rv.each do |value| %>
|
||||||
|
<p style="word-break: break-all"><%= value[0] %> => <%= value[1] %></p>
|
||||||
|
<% end %>
|
||||||
|
<br>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-1 pure-u-md-1-5">
|
<div class="pure-u-1 pure-u-md-1-5">
|
||||||
<% related_videos_list.each do |video| %>
|
<% rvs.each do |rv| %>
|
||||||
<a class="link" href="/watch?v=<%= video.id %>"><p><%= video.info["title"] %></p></a>
|
<% if rv.has_key?("id") %>
|
||||||
<% end %>
|
<p><a class="link" href="/watch?v=<%= rv["id"] %>"><%= rv["title"] %></a></p>
|
||||||
</div>
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
Loading…
Reference in New Issue
Block a user