kopia lustrzana https://github.com/iv-org/invidious
				
				
				
			Freshen up for the big dance
							rodzic
							
								
									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> | ||||||
		Ładowanie…
	
		Reference in New Issue
	
	 Omar Roth
						Omar Roth