Add view counter, likes/dislikes, rating, and HTML parser
This commit is contained in:
parent
131b92b381
commit
31a3e1bb3a
|
@ -11,6 +11,8 @@ targets:
|
||||||
dependencies:
|
dependencies:
|
||||||
kemal:
|
kemal:
|
||||||
github: kemalcr/kemal
|
github: kemalcr/kemal
|
||||||
|
pg:
|
||||||
|
github: will/crystal-pg
|
||||||
|
|
||||||
crystal: 0.23.1
|
crystal: 0.23.1
|
||||||
|
|
||||||
|
|
108
src/visor.cr
108
src/visor.cr
|
@ -1,25 +1,56 @@
|
||||||
require "kemal"
|
|
||||||
require "xml"
|
|
||||||
require "http/client"
|
require "http/client"
|
||||||
require "base64"
|
require "json"
|
||||||
|
require "kemal"
|
||||||
|
require "pg"
|
||||||
|
require "xml"
|
||||||
|
|
||||||
macro templated(filename)
|
macro templated(filename)
|
||||||
render "views/#{{{filename}}}.ecr", "views/layout.ecr"
|
render "views/#{{{filename}}}.ecr", "views/layout.ecr"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# pg = DB.open("postgres://kemal@visor/dev")
|
||||||
|
|
||||||
|
alias Type = String | Hash(String, Type)
|
||||||
|
|
||||||
|
def object_to_hash(value)
|
||||||
|
object = {} of String => Type
|
||||||
|
items = value.split("&")
|
||||||
|
items.each do |item|
|
||||||
|
key, value = item.split("=")
|
||||||
|
value = URI.unescape(value)
|
||||||
|
object[key] = parse_uri(value)
|
||||||
|
end
|
||||||
|
return object
|
||||||
|
end
|
||||||
|
|
||||||
|
def array_to_hash(value)
|
||||||
|
array = {} of String => Type
|
||||||
|
items = value.split(",")
|
||||||
|
count = 0
|
||||||
|
items.each do |item|
|
||||||
|
array[count.to_s] = parse_uri(item)
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
return array
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_uri(value)
|
||||||
|
if value.starts_with?("http") || value.starts_with?("[")
|
||||||
|
return value
|
||||||
|
else
|
||||||
|
if value.includes?(",")
|
||||||
|
return array_to_hash(value)
|
||||||
|
elsif value.includes?("&")
|
||||||
|
return object_to_hash(value)
|
||||||
|
else
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context = OpenSSL::SSL::Context::Client.insecure
|
context = OpenSSL::SSL::Context::Client.insecure
|
||||||
client = HTTP::Client.new("www.youtube.com", 443, context)
|
client = HTTP::Client.new("www.youtube.com", 443, context)
|
||||||
|
|
||||||
def params_to_hash(params)
|
|
||||||
pairs = params.split("&")
|
|
||||||
hash = Hash(String, String).new
|
|
||||||
pairs.each do |pair|
|
|
||||||
key, value = pair.split("=")
|
|
||||||
hash[key] = URI.unescape(value)
|
|
||||||
end
|
|
||||||
return hash
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/" do |env|
|
get "/" do |env|
|
||||||
templated "index"
|
templated "index"
|
||||||
end
|
end
|
||||||
|
@ -27,42 +58,37 @@ end
|
||||||
get "/watch/:video_id" do |env|
|
get "/watch/:video_id" do |env|
|
||||||
video_id = env.params.url["video_id"]
|
video_id = env.params.url["video_id"]
|
||||||
|
|
||||||
if File.exists?("video_info/#{video_id}")
|
video_info_encoded = HTTP::Client.get("https://www.youtube.com/get_video_info?video_id=#{video_id}&el=info&ps=default&eurl=&gl=US&hl=en", nil, nil, tls = context).body
|
||||||
video_info = JSON.parse(File.open("video_info/#{video_id}"))
|
video_info = object_to_hash(video_info_encoded)
|
||||||
|
body = client.get("/watch?v=#{video_id}").body
|
||||||
|
doc = XML.parse(body)
|
||||||
|
|
||||||
|
likes = doc.xpath_node(%q(//button[@title="I like this"]/span))
|
||||||
|
if likes
|
||||||
|
likes = likes.content
|
||||||
else
|
else
|
||||||
video_info_encoded = HTTP::Client.get("https://www.youtube.com/get_video_info?video_id=#{video_id}&el=info&ps=default&eurl=&gl=US&hl=en", nil, nil, tls = context).body
|
likes = "n/a"
|
||||||
video_info = params_to_hash(video_info_encoded)
|
|
||||||
|
|
||||||
File.write("video_info/#{video_id}", video_info.to_json)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
fmt_stream_map = video_info["url_encoded_fmt_stream_map"].to_s.split(",")
|
dislikes = doc.xpath_node(%q(//button[@title="I dislike this"]/span))
|
||||||
fmt_stream = Array(Hash(String, String)).new
|
if dislikes
|
||||||
fmt_stream_map.each do |fmt|
|
dislikes.content
|
||||||
fmt_stream << params_to_hash(fmt.to_s)
|
else
|
||||||
|
dislikes = "n/a"
|
||||||
end
|
end
|
||||||
fmt_stream.reverse!
|
|
||||||
|
File.write("video_info/#{video_id}", video_info.to_json)
|
||||||
templated "watch"
|
templated "watch"
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/listen/:video_id" do |env|
|
# get "/listen/:video_id" do |env|
|
||||||
video_id = env.params.url["video_id"]
|
# video_id = env.params.url["video_id"]
|
||||||
|
|
||||||
if File.exists?("video_info/#{video_id}")
|
# video_info_encoded = HTTP::Client.get("https://www.youtube.com/get_video_info?video_id=#{video_id}&el=info&ps=default&eurl=&gl=US&hl=en", nil, nil, tls = context).body
|
||||||
video_info = JSON.parse(File.open("video_info/#{video_id}"))
|
# video_info = object_to_hash(video_info_encoded)
|
||||||
else
|
# File.write("video_info/#{video_id}", video_info.to_json)
|
||||||
video_info_encoded = HTTP::Client.get("https://www.youtube.com/get_video_info?video_id=#{video_id}&el=info&ps=default&eurl=&gl=US&hl=en", nil, nil, tls = context).body
|
# templated "listen"
|
||||||
video_info = params_to_hash(video_info_encoded)
|
# end
|
||||||
|
|
||||||
File.write("video_info/#{video_id}", video_info.to_json)
|
|
||||||
end
|
|
||||||
|
|
||||||
adaptive_fmt = Array(Hash(String, String)).new
|
|
||||||
video_info["adaptive_fmts"].to_s.split(",") do |fmt|
|
|
||||||
adaptive_fmt << params_to_hash(video_info["adaptive_fmts"].to_s)
|
|
||||||
end
|
|
||||||
templated "listen"
|
|
||||||
end
|
|
||||||
|
|
||||||
public_folder "assets"
|
public_folder "assets"
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
<h1><%= URI.unescape(video_info["title"].to_s,true) %></h1>
|
<% title = URI.unescape(video_info["title"].as(String), true) %>
|
||||||
<video style="width: 100%" poster="<%= video_info["iurlmq"] %>" controls>
|
<h1><%= title %></h1>
|
||||||
<% adaptive_fmt.each do |fmt| %>
|
<video style="width: 100%" poster="<%= video_info["iurlhq720"] %>" controls>
|
||||||
<% fmt_type = fmt["type"].to_s.split(";")[0] %>
|
<% video_info["adaptive_fmts"].as(Hash).each do |key, value| %>
|
||||||
<% if fmt_type.starts_with?("audio") %>
|
<% url = value["url"] %>
|
||||||
<source src="<%= fmt["url"] %>" type="<%= fmt_type %>">
|
<% type = value["type"].to_s.split(";")[0] %>
|
||||||
|
<% if type.starts_with?("audio") %>
|
||||||
|
<source src="<%= url %>" type="<%= type %>">
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</video>
|
</video>
|
||||||
|
|
||||||
|
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
<div class="pure-u-1 pure-u-md-1-5"></div>
|
<div class="pure-u-1 pure-u-md-1-5"></div>
|
||||||
<div class="pure-u-1 pure-u-md-3-5"></div>
|
<div class="pure-u-1 pure-u-md-3-5"></div>
|
||||||
<div class="pure-u-1 pure-u-md-1-5"></div>
|
<div class="pure-u-1 pure-u-md-1-5">
|
||||||
|
<p>Views : <%= video_info["view_count"] %></p>
|
||||||
|
<p>Rating : <%= video_info["avg_rating"] %></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,15 +1,20 @@
|
||||||
<h1><%= URI.unescape(video_info["title"].to_s,true) %></h1>
|
<% title = URI.unescape(video_info["title"].as(String), true) %>
|
||||||
<video style="width: 100%" poster="<%= video_info["iurlmq"] %>" controls>
|
<h1><%= title %></h1>
|
||||||
<% fmt_stream.each do |fmt| %>
|
<video style="width: 100%" poster="<%= video_info["iurl"] %>" controls>
|
||||||
<source src="<%= fmt["url"] %>" type="<%= fmt["type"].to_s.split(";")[0] %>">
|
<% video_info["url_encoded_fmt_stream_map"].as(Hash).each do |key, value| %>
|
||||||
<% end %>
|
<% url = value["url"] %>
|
||||||
|
<% type = value["type"]["0"].to_s.split(";")[0] %>
|
||||||
|
<source src="<%= url %>" type="<%= type %>">
|
||||||
|
<% end %>
|
||||||
</video>
|
</video>
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
<div class="pure-u-1 pure-u-md-1-5"></div>
|
<div class="pure-u-1 pure-u-md-1-5">
|
||||||
<div class="pure-u-1 pure-u-md-3-5">
|
<p>Likes: <%= likes %></p>
|
||||||
<% fmt_stream.each do |fmt| %>
|
<p>Dislikes: <%= dislikes %></p>
|
||||||
<p><%= fmt["quality"] %></p>
|
</div>
|
||||||
<% end %>
|
<div class="pure-u-1 pure-u-md-3-5"></div>
|
||||||
</div>
|
<div class="pure-u-1 pure-u-md-1-5">
|
||||||
<div class="pure-u-1 pure-u-md-1-5"></div>
|
<p>Views : <%= video_info["view_count"] %></p>
|
||||||
|
<p>Rating : <%= video_info["avg_rating"] %></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
Loading…
Reference in a new issue