Initial commit
This commit is contained in:
commit
26959020b7
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@ -0,0 +1,7 @@
|
||||
[*.cr]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/doc/
|
||||
/lib/
|
||||
/bin/
|
||||
/.shards/
|
||||
/video_info/
|
||||
/.vscode/
|
||||
visor
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Omar Roth
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# visor
|
||||
|
||||
TODO: Write a description here
|
||||
|
||||
## Installation
|
||||
|
||||
TODO: Write installation instructions here
|
||||
|
||||
## Usage
|
||||
|
||||
TODO: Write usage instructions here
|
||||
|
||||
## Development
|
||||
|
||||
TODO: Write development instructions here
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork it ( https://github.com/[your-github-name]/visor/fork )
|
||||
2. Create your feature branch (git checkout -b my-new-feature)
|
||||
3. Commit your changes (git commit -am 'Add some feature')
|
||||
4. Push to the branch (git push origin my-new-feature)
|
||||
5. Create a new Pull Request
|
||||
|
||||
## Contributors
|
||||
|
||||
- [[your-github-name]](https://github.com/[your-github-name]) Omar Roth - creator, maintainer
|
7
assets/css/grids-responsive-min.css
vendored
Normal file
7
assets/css/grids-responsive-min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
11
assets/css/pure-min.css
vendored
Normal file
11
assets/css/pure-min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4
assets/js/jquery-min.js
vendored
Normal file
4
assets/js/jquery-min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
17
shard.yml
Normal file
17
shard.yml
Normal file
@ -0,0 +1,17 @@
|
||||
name: visor
|
||||
version: 0.1.0
|
||||
|
||||
authors:
|
||||
- Omar Roth <omarroth@hotmail.com>
|
||||
|
||||
targets:
|
||||
visor:
|
||||
main: src/visor.cr
|
||||
|
||||
dependencies:
|
||||
kemal:
|
||||
github: kemalcr/kemal
|
||||
|
||||
crystal: 0.23.1
|
||||
|
||||
license: MIT
|
0
src/proxy.cr
Normal file
0
src/proxy.cr
Normal file
69
src/visor.cr
Normal file
69
src/visor.cr
Normal file
@ -0,0 +1,69 @@
|
||||
require "kemal"
|
||||
require "xml"
|
||||
require "http/client"
|
||||
require "base64"
|
||||
|
||||
macro templated(filename)
|
||||
render "views/#{{{filename}}}.ecr", "views/layout.ecr"
|
||||
end
|
||||
|
||||
context = OpenSSL::SSL::Context::Client.insecure
|
||||
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|
|
||||
templated "index"
|
||||
end
|
||||
|
||||
get "/watch/:video_id" do |env|
|
||||
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 = params_to_hash(video_info_encoded)
|
||||
|
||||
File.write("video_info/#{video_id}", video_info.to_json)
|
||||
end
|
||||
|
||||
fmt_stream_map = video_info["url_encoded_fmt_stream_map"].to_s.split(",")
|
||||
fmt_stream = Array(Hash(String, String)).new
|
||||
fmt_stream_map.each do |fmt|
|
||||
fmt_stream << params_to_hash(fmt.to_s)
|
||||
end
|
||||
fmt_stream.reverse!
|
||||
templated "watch"
|
||||
end
|
||||
|
||||
get "/listen/:video_id" do |env|
|
||||
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 = params_to_hash(video_info_encoded)
|
||||
|
||||
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"
|
||||
|
||||
Kemal.run
|
0
views/index.ecr
Normal file
0
views/index.ecr
Normal file
23
views/layout.ecr
Normal file
23
views/layout.ecr
Normal file
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Visor</title>
|
||||
<meta content="">
|
||||
<link rel="stylesheet" href="/css/pure-min.css">
|
||||
<link rel="stylesheet" href="/css/grids-responsive-min.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1 pure-u-md-1-5"></div>
|
||||
<div class="pure-u-1 pure-u-md-3-5">
|
||||
<%= content %>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-md-1-5"></div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
16
views/listen.ecr
Normal file
16
views/listen.ecr
Normal file
@ -0,0 +1,16 @@
|
||||
<h1><%= URI.unescape(video_info["title"].to_s,true) %></h1>
|
||||
<video style="width: 100%" poster="<%= video_info["iurlmq"] %>" controls>
|
||||
<% adaptive_fmt.each do |fmt| %>
|
||||
<% fmt_type = fmt["type"].to_s.split(";")[0] %>
|
||||
<% if fmt_type.starts_with?("audio") %>
|
||||
<source src="<%= fmt["url"] %>" type="<%= fmt_type %>">
|
||||
<% end %>
|
||||
<% end %>
|
||||
</video>
|
||||
|
||||
|
||||
<div class="pure-g">
|
||||
<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-1-5"></div>
|
||||
</div>
|
15
views/watch.ecr
Normal file
15
views/watch.ecr
Normal file
@ -0,0 +1,15 @@
|
||||
<h1><%= URI.unescape(video_info["title"].to_s,true) %></h1>
|
||||
<video style="width: 100%" poster="<%= video_info["iurlmq"] %>" controls>
|
||||
<% fmt_stream.each do |fmt| %>
|
||||
<source src="<%= fmt["url"] %>" type="<%= fmt["type"].to_s.split(";")[0] %>">
|
||||
<% end %>
|
||||
</video>
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1 pure-u-md-1-5"></div>
|
||||
<div class="pure-u-1 pure-u-md-3-5">
|
||||
<% fmt_stream.each do |fmt| %>
|
||||
<p><%= fmt["quality"] %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-md-1-5"></div>
|
||||
</div>
|
83
youtube api.md
Normal file
83
youtube api.md
Normal file
@ -0,0 +1,83 @@
|
||||
# YOUTUBE API URLS
|
||||
|
||||
## Search
|
||||
```curl
|
||||
https://www.youtube.com/results BASE URL
|
||||
?q= QUERY
|
||||
&page= PAGE
|
||||
|
||||
&sp=EgIQAVAU FOR STREAM
|
||||
&sp=EgIQAlAU FOR CHANNEL
|
||||
&sp=EgIQA1AU FOR PLAYLIST
|
||||
```
|
||||
|
||||
## Channel
|
||||
```curl
|
||||
https://www.youtube.com/feeds/videos.xml BASE URL
|
||||
?channel_id= CHANNEL ID
|
||||
|
||||
https://www.youtube.com/channel/:ID/videos CLEAN URL
|
||||
|
||||
?view=0 VIDEO PARAMS
|
||||
&flow=list |
|
||||
&sort=dd |
|
||||
&live_view=10000 |
|
||||
```
|
||||
|
||||
## Stream
|
||||
```curl
|
||||
https://www.youtube.com/get_video_info BSAE URL
|
||||
?video_id= VIDEO_ID
|
||||
&el=info
|
||||
&ps=default
|
||||
&eurl=
|
||||
&gl=US
|
||||
&hl=en
|
||||
|
||||
https://www.youtube.com/embed/:ID
|
||||
|
||||
|
||||
https://www.youtube.com/get_video_info?video_id= + video_id +
|
||||
&el=info&ps=default&eurl=&gl=US&hl=en"&el=info&ps=default&eurl=&gl=US&hl=en
|
||||
|
||||
```
|
||||
|
||||
Pulled from [here](https://github.com/TeamNewPipe/NewPipeExtractor/tree/master/src/main/java/org/schabi/newpipe/extractor/services/youtube)
|
||||
|
||||
---
|
||||
|
||||
```
|
||||
ctoken EhgSBmNvbG9ycxoOU0l3QlVCVHFBd0ElM0QYvN7oGA%253D%253D
|
||||
itct CBoQuy8iEwjrn57J94vWAhXFn64KHUCuBss%3D
|
||||
|
||||
ctoken EhoSBmNvbG9ycxoQU0ZCUUZPb0RBQSUzRCUzRBi83ugY
|
||||
itct CBoQuy8iEwj4g4TF94vWAhUBZq4KHdF7DWs%3D
|
||||
|
||||
ctoken EhoSBmNvbG9ycxoQU0dSUUZPb0RBQSUzRCUzRBi83ugY
|
||||
itct CBoQuy8iEwierb_G94vWAhUTdq4KHcWVCTI%3D
|
||||
|
||||
ctoken EhoSBmNvbG9ycxoQU0hoUUZPb0RBQSUzRCUzRBi83ugY
|
||||
itct CBoQuy8iEwiZwfvH94vWAhXCiq4KHa82A70%3D
|
||||
|
||||
ctoken EhoSBmNvbG9ycxoQU0JSUUZPb0RBQSUzRCUzRBi83ugY
|
||||
itct CD0Quy8YACITCOKdxPf2i9YCFVBOrgodqy8K0Cj0JA%3D%3D
|
||||
|
||||
|
||||
|
||||
Hex 12 1a 12 06
|
||||
Hex 12 18 12 06
|
||||
Padding?
|
||||
| Query: colors
|
||||
| |
|
||||
ctoken EhgS BmNvbG9ycx oOU0 l3 QlVCVHFBd0ElM0QYvN7oGA%253D%253D
|
||||
ctoken EhoS BmNvbG9ycx oQU0 ZC UUZPb0RBQSUzRCUzRBi83ugY
|
||||
ctoken EhoS BmNvbG9ycx oQU0 dS UUZPb0RBQSUzRCUzRBi83ugY
|
||||
ctoken EhoS BmNvbG9ycx oQU0 ho UUZPb0RBQSUzRCUzRBi83ugY
|
||||
ctoken EhoS BmNvbG9ycx oQU0 JS UUZPb0RBQSUzRCUzRBi83ugY
|
||||
|
||||
itct CBoQuy8iEw jrn57J 94vWAh XFn 64KH UCuBss%3D
|
||||
itct CBoQuy8iEw j4g4TF 94vWAh UBZ q4KH dF7DWs%3D
|
||||
itct CBoQuy8iEw ierb_G 94vWAh UTd q4KH cWVCTI%3D
|
||||
itct CBoQuy8iEw iZwfvH 94vWAh XCi q4KH a82A70%3D
|
||||
itct CD0Quy8YAC ITCOKd xPf2i9 YCF VBOr godqy8K0Cj0JA%3D%3D
|
||||
```
|
Loading…
Reference in New Issue
Block a user