Add view counter, likes/dislikes, rating, and HTML parser

pull/3/head
Omar Roth 7 years ago
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

@ -1,25 +1,56 @@
require "http/client"
require "json"
require "kemal" require "kemal"
require "pg"
require "xml" require "xml"
require "http/client"
require "base64"
macro templated(filename) macro templated(filename)
render "views/#{{{filename}}}.ecr", "views/layout.ecr" render "views/#{{{filename}}}.ecr", "views/layout.ecr"
end end
context = OpenSSL::SSL::Context::Client.insecure # pg = DB.open("postgres://kemal@visor/dev")
client = HTTP::Client.new("www.youtube.com", 443, context)
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 params_to_hash(params) def array_to_hash(value)
pairs = params.split("&") array = {} of String => Type
hash = Hash(String, String).new items = value.split(",")
pairs.each do |pair| count = 0
key, value = pair.split("=") items.each do |item|
hash[key] = URI.unescape(value) array[count.to_s] = parse_uri(item)
count += 1
end end
return hash return array
end 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
client = HTTP::Client.new("www.youtube.com", 443, context)
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 = JSON.parse(File.open("video_info/#{video_id}"))
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 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 = params_to_hash(video_info_encoded) video_info = object_to_hash(video_info_encoded)
body = client.get("/watch?v=#{video_id}").body
File.write("video_info/#{video_id}", video_info.to_json) doc = XML.parse(body)
end
fmt_stream_map = video_info["url_encoded_fmt_stream_map"].to_s.split(",") likes = doc.xpath_node(%q(//button[@title="I like this"]/span))
fmt_stream = Array(Hash(String, String)).new if likes
fmt_stream_map.each do |fmt| likes = likes.content
fmt_stream << params_to_hash(fmt.to_s) else
end likes = "n/a"
fmt_stream.reverse!
templated "watch"
end end
get "/listen/:video_id" do |env| dislikes = doc.xpath_node(%q(//button[@title="I dislike this"]/span))
video_id = env.params.url["video_id"] if dislikes
dislikes.content
if File.exists?("video_info/#{video_id}")
video_info = JSON.parse(File.open("video_info/#{video_id}"))
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 dislikes = "n/a"
video_info = params_to_hash(video_info_encoded) end
File.write("video_info/#{video_id}", video_info.to_json) File.write("video_info/#{video_id}", video_info.to_json)
templated "watch"
end end
adaptive_fmt = Array(Hash(String, String)).new # get "/listen/:video_id" do |env|
video_info["adaptive_fmts"].to_s.split(",") do |fmt| # video_id = env.params.url["video_id"]
adaptive_fmt << params_to_hash(video_info["adaptive_fmts"].to_s)
end # 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 = object_to_hash(video_info_encoded)
end # File.write("video_info/#{video_id}", video_info.to_json)
# 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| %>
<% url = value["url"] %>
<% type = value["type"]["0"].to_s.split(";")[0] %>
<source src="<%= url %>" type="<%= type %>">
<% 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 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 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 class="pure-u-1 pure-u-md-1-5"></div>
</div> </div>
Loading…
Cancel
Save