v1.0
parent
859c990ba0
commit
ba1a1eb712
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
header("Content-Type: application/json");
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
|
||||
if(isset($_GET["vid"])){
|
||||
|
||||
|
||||
$ytpage = file_get_contents("https://www.youtube.com/watch?v=".$_GET["vid"]);
|
||||
|
||||
unset($_COOKIE);
|
||||
|
||||
$pattern = "/ytplayer.config\ \=\ ({.+}});/";
|
||||
|
||||
preg_match_all($pattern, $ytpage, $matches);
|
||||
$json = $matches[1][0];
|
||||
|
||||
//parse informations
|
||||
|
||||
$json = json_decode($json);
|
||||
|
||||
$ytdata = $json->args->player_response;
|
||||
|
||||
$ytdata = json_decode($ytdata);
|
||||
|
||||
if($ytdata->videoDetails->useCipher == false){
|
||||
|
||||
$data = new stdClass();
|
||||
|
||||
$data->title = $ytdata->videoDetails->title;
|
||||
$data->channel = $ytdata->videoDetails->author;
|
||||
$data->videoId = $ytdata->videoDetails->videoId;
|
||||
$data->length = $ytdata->videoDetails->lengthSeconds;
|
||||
$data->views = $ytdata->videoDetails->viewCount;
|
||||
|
||||
$data->sources = $ytdata->streamingData;
|
||||
$data->thumbnails = $ytdata->videoDetails->thumbnail->thumbnails;
|
||||
|
||||
$send = json_encode($data);
|
||||
|
||||
echo $send;
|
||||
|
||||
}else{
|
||||
$data = new stdClass();
|
||||
$data->error = "cipher_video";
|
||||
$send = json_encode($data);
|
||||
echo $send;
|
||||
}
|
||||
|
||||
}else{
|
||||
$data = new stdClass();
|
||||
$data->error = "missing_video_id";
|
||||
$send = json_encode($data);
|
||||
echo $send;
|
||||
}
|
||||
?>
|
||||
@ -0,0 +1,59 @@
|
||||
<h1>API for Developers</h1>
|
||||
<p>You can get the data of a video very easily by using our API.</p>
|
||||
|
||||
<h2>Web Request structure</h2>
|
||||
<span class="label"><span class="label-name" style="width: 70px;display: inline-block;">Method</span><span class="label-value label-green">GET</span></span>
|
||||
<span class="label"><span class="label-name" style="width: 70px;display: inline-block;">Url</span><span class="label-value label-blue">https://feuerhamster.code-elite.net/web-youtube-downloader/api.php</span></span>
|
||||
<span class="label"><span class="label-name" style="width: 70px;display: inline-block;">Params</span><span class="label-value label-purble">vid={YOUTUBE VIDEO ID}</span></span>
|
||||
<span class="label"><span class="label-name" style="width: 70px;display: inline-block;">Return</span><span class="label-value label-orange">JSON</span></span>
|
||||
|
||||
<h2 style="margin-top: 40px;">Return values</h2>
|
||||
<p>There are mulitple return values for that request. The return values are also in JSON format</p>
|
||||
<div class="pre">Errors:
|
||||
- error: missing_video_id //returns if you have not send the video Id in the query string
|
||||
- error: cipher_video" //returns if the video is protected and can not be read by the api
|
||||
</div>
|
||||
|
||||
<div class="pre">Video Data JSON structure:
|
||||
|
||||
- title
|
||||
- channel
|
||||
- length
|
||||
- views
|
||||
|
||||
- sources:
|
||||
|
||||
- expiresInSeconds
|
||||
|
||||
- formats:
|
||||
ARRAY()
|
||||
|
||||
- adaptiveFormats:
|
||||
ARRAY()
|
||||
|
||||
- thumbnails:
|
||||
ARRAY()
|
||||
</div>
|
||||
|
||||
|
||||
<h2 style="margin-top: 40px;">Examples</h2>
|
||||
<p>An example url for an api call</p>
|
||||
<div class="pre">https://feuerhamster.code-elite.net/web-youtube-downloader/api.php?vid=nD6_aQIJgW0
|
||||
</div class="pre">
|
||||
|
||||
<p>An example with Ajax in JavaScript</p>
|
||||
<div class="pre">var videoId = "nD6_aQIJgW0";
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: 'https://feuerhamster.code-elite.net/web-youtube-downloader/api.php',
|
||||
data: 'vid=' + videoId,
|
||||
success: function(res){
|
||||
|
||||
if(!res.error){
|
||||
console.log(res);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
</div>
|
||||
@ -0,0 +1,31 @@
|
||||
<div class="box box-mobile">
|
||||
|
||||
<img id="video-thumbnail" style="max-height: 160px;">
|
||||
<div>
|
||||
<h1 id="video-title" style="margin: 0px 0px 0px 20px;">...</h1>
|
||||
<h2 id="video-time" style="margin: 0px 0px 0px 20px; color: #9e4b8b;">...</h2>
|
||||
<h2 id="video-views" style="margin: 0px 0px 0px 20px; color: #9e4b8b;">...</h2>
|
||||
<h2 id="video-channel" style="margin: 0px 0px 0px 20px; color: rgb(120,120,120)">...</h2>
|
||||
<h3 id="video-links" style="margin: 0px 0px 0px 20px;">...</h3>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<h1>Main Sources</h1>
|
||||
|
||||
<div id="video-main-source">
|
||||
|
||||
</div>
|
||||
|
||||
<h1>Adaptive Sources</h1>
|
||||
|
||||
<div id="video-sources">
|
||||
|
||||
</div>
|
||||
|
||||
<h1>Thumbnails</h1>
|
||||
|
||||
<div id="video-thumbnails">
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,9 @@
|
||||
<div id="home-page">
|
||||
|
||||
<h1 style="font-size: 42px">Download Youtube Videos from Source!</h1>
|
||||
|
||||
<h2 style="margin-bottom: 50px;">All Video and Audio Tracks + Thumbnails</h2>
|
||||
|
||||
<input type="text" id="home-video-url" placeholder="Paste your Video URL" onchange="loadVideoURL(this.value);" />
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,107 @@
|
||||
//get query string
|
||||
var urlQs = document.URL.split('?');
|
||||
|
||||
//check if any querystring is set
|
||||
if(urlQs[1]){
|
||||
|
||||
//parse querytring args
|
||||
var qsArgs = urlQs[1].split('=');
|
||||
|
||||
if(qsArgs[0] == "vid"){
|
||||
|
||||
$('#content').load('./downloader.html');
|
||||
getVideoData(qsArgs[1]);
|
||||
|
||||
}else if(qsArgs[0] == "page"){
|
||||
if(qsArgs[1] == "infos"){
|
||||
$('#content').load('./infos.html');
|
||||
}else if(qsArgs[1] == "documentation"){
|
||||
$('#content').load('./docs.php');
|
||||
}else{
|
||||
$('#content').html('<center><h1>ERROR 404: Page not found!</h1></center>');
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
$('#content').load('./home.html');
|
||||
}
|
||||
|
||||
|
||||
function parseMimeType(mimeType){
|
||||
var regex = /(\w+)\/(\w+)\;\ codecs\=\"(.+)\"/;
|
||||
var result = regex.exec(mimeType);
|
||||
return { type: result[1], format: result[2], codec: result[3] };
|
||||
}
|
||||
|
||||
function secToMin(time) {
|
||||
var hr = ~~(time / 3600);
|
||||
var min = ~~((time % 3600) / 60);
|
||||
var sec = time % 60;
|
||||
var sec_min = "";
|
||||
if (hr > 0) {
|
||||
sec_min += "" + hrs + ":" + (min < 10 ? "0" : "");
|
||||
}
|
||||
sec_min += "" + min + ":" + (sec < 10 ? "0" : "");
|
||||
sec_min += "" + sec;
|
||||
return sec_min+ " minutes";
|
||||
}
|
||||
|
||||
function getVideoData(videoId){
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "./api.php",
|
||||
data: "vid=" + videoId,
|
||||
success: function(res){
|
||||
|
||||
console.log(res);
|
||||
|
||||
if(!res.error){
|
||||
|
||||
$('#video-title').html(res.title);
|
||||
$('#video-channel').html(res.channel);
|
||||
$('#video-views').html(res.views.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,') + " views");
|
||||
$('#video-time').html(secToMin(res.length));
|
||||
$('#video-thumbnail').attr("src", res.thumbnails[3].url);
|
||||
|
||||
$('#video-links').html('<a href="https://www.youtube.com/watch?v=' + res.videoId + '" style="color: #2980b9" target="_blank">https://www.youtube.com/watch?v=' + res.videoId + '<a>');
|
||||
|
||||
res.sources.formats.forEach(element => {
|
||||
|
||||
var mainMime = parseMimeType(element.mimeType);
|
||||
$('#video-main-source').append('<div class="box box-mobile"> <video src="' + element.url + '" controls height="190px"></video> <div style="padding: 10px 20px 10px 20px"> <h2 style="margin-top: 0px; margin-bottom: 10px; font-weight: 100"><b style="font-weight: 700">Quality:</b> ' +element.qualityLabel+ ' </h2> <h2 style="margin-top: 0px; margin-bottom: 10px; font-weight: 100"><b style="font-weight: 700">Format:</b> ' + mainMime.format + ' </h2> <h2 style="margin-top: 0px; margin-bottom: 10px; font-weight: 100"><b style="font-weight: 700">Codec:</b> ' + mainMime.codec + ' </h2> <a href="' + element.url + '" target="_blank" class="download-link-large"><i class="fas fa-external-link-alt"></i> Download</a> </div></div>');
|
||||
|
||||
});
|
||||
|
||||
res.sources.adaptiveFormats.forEach(element => {
|
||||
var mime = parseMimeType(element.mimeType);
|
||||
if(mime.type == "video"){
|
||||
$('#video-sources').append('<div class="box" style="margin: 10px 0px 10px 0px;"><span class="label"><span class="label-name">Type</span><span class="label-value label-red">' + mime.type + '</span></span><span class="label"><span class="label-name">Quality</span><span class="label-value label-green">' + element.qualityLabel + '</span></span><span class="label"><span class="label-name">Format</span><span class="label-value label-orange">' + mime.format + '</span></span><span class="label"><span class="label-name">Codec</span><span class="label-value label-purble">' + mime.codec + '</span></span> <div class="spacer"></div> <a href="' + element.url + '" target="_blank" style="color: rgb(50,50,50); font-size: 26px;"><i class="fas fa-external-link-alt"></i></a> </div>');
|
||||
}else{
|
||||
$('#video-sources').append('<div class="box" style="margin: 10px 0px 10px 0px;"><span class="label"><span class="label-name">Type</span><span class="label-value label-blue">' + mime.type + '</span></span><span class="label"><span class="label-name">Bitrate</span><span class="label-value label-green">' + element.bitrate + '</span></span><span class="label"><span class="label-name">Format</span><span class="label-value label-orange">' + mime.format + '</span></span><span class="label"><span class="label-name">Codec</span><span class="label-value label-purble">' + mime.codec + '</span></span> <div class="spacer"></div> <a href="' + element.url + '" target="_blank" style="color: rgb(50,50,50); font-size: 26px;"><i class="fas fa-external-link-alt"></i></a> </div>');
|
||||
}
|
||||
});
|
||||
|
||||
res.thumbnails.forEach(element => {
|
||||
$('#video-thumbnails').append('<div class="box box-mobile" style="margin: 10px 0px 10px 0px; flex-direction: row"><img src="' + element.url + '" style="width: 200px;" /><div style="padding: 10px 20px 10px 20px"><span class="label" style="margin: 0px;"><span class="label-name">Size</span><span class="label-value label-green">' + element.width + 'px*' + element.height + 'px</span></span><br/><a href="' + element.url + '" target="_blank" class="download-link-large" style="font-size: 20px;" download="' + element.url + '"><i class="fas fa-external-link-alt"></i> Download</a></div></div>')
|
||||
});
|
||||
|
||||
}else{
|
||||
$('#content').html('<center><h1>An error has occurred!</h1><h2>Please try another video or try again later</h2></center>');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function loadVideoURL(source){
|
||||
|
||||
//parse soruce and get id
|
||||
var ytidRegex = /(youtu\.be\/|youtube\.com\/(watch\?(.*&)?v=|(embed|v)\/))([^\?&"'>]+)/;
|
||||
var videoId = ytidRegex.exec(source)[5];
|
||||
|
||||
window.location.href = window.location.protocol + "//" + window.location.hostname + window.location.pathname + "?vid=" + videoId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.4.1.min.js"
|
||||
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
<title>Web-Youtube-Downloader</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=400, initial-scale=0.9">
|
||||
<meta name="description" content="Get data of youtube videos and download the sources">
|
||||
|
||||
<link rel="stylesheet" href="style.css?v=2" />
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">
|
||||
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<div id="head-bar">
|
||||
|
||||
<h1 onclick="window.location.href='./';" style="cursor: pointer;"> <i class="fab fa-youtube"></i> Web-Youtube-Downloader</h1>
|
||||
|
||||
<div class="spacer"></div>
|
||||
|
||||
<input type="text" id="headbar-video-url" placeholder="Paste your video URL" onchange="loadVideoURL(this.value); this.value = '';" />
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<a href="?page=documentation">Developer API</a> <a href="https://github.com/Feuerhamster/web-youtube-downloader" target="_blank">GitHub</a> <a href="?page=infos">Disclaimer/Informations</a>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<script src="index.js"></script>
|
||||
@ -0,0 +1,26 @@
|
||||
<h1>Disclaimer</h1>
|
||||
<p>This Website is not a part of youtube or google</p>
|
||||
|
||||
<h1>Infos</h1>
|
||||
<p>
|
||||
<b>Contact the owner:</b> <br/><br/>
|
||||
<b>Email: </b> myhamstermail@gmail.com<br/>
|
||||
<b>GitHub: </b> github.com/Feuerhamster<br/>
|
||||
|
||||
<br/><br/>
|
||||
|
||||
<b>Where do we have the data of the youtube videos?</b><br/><br/>
|
||||
We use the official data from the youtube.com website. All URLs and metadata come from the respective page of the corresponding Youtube video.<br/><br/>
|
||||
|
||||
<br/><br/>
|
||||
|
||||
<b>Is the downloading of youtube videos lawful?</b><br/><br/>
|
||||
Everyone is allowed to download public Youtube videos for private use.<br/><br/>
|
||||
|
||||
<br/><br/>
|
||||
|
||||
<b>Does this website violate laws and regulations such as once "convert2mp3"?</b><br/><br/>
|
||||
No. On "convert2mp3" the videos were converted on the servers of the provider and made available for download.<br/>
|
||||
On our website, you download the videos directly from the sources on the google server.
|
||||
|
||||
</p>
|
||||
@ -0,0 +1,180 @@
|
||||
body, html{
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-family: 'Muli', sans-serif;
|
||||
}
|
||||
|
||||
*{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, p{
|
||||
color: rgb(50,50,50);
|
||||
}
|
||||
|
||||
@media (max-width:901px){
|
||||
.box-mobile{
|
||||
flex-direction: column!important;
|
||||
align-items: center;
|
||||
}
|
||||
.box{
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.pre{
|
||||
background-color: rgba(240,240,240);
|
||||
border: 2px solid rgba(230,230,230);
|
||||
border-radius: 2px;
|
||||
padding: 10px;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
color: rgb(50,50,50);
|
||||
overflow-x: auto;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
#head-bar{
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
background-color: #d63030;
|
||||
padding: 5px;
|
||||
box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.3);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#head-bar > h1{
|
||||
color: white;
|
||||
margin: 0px;
|
||||
font-family: 'Muli', sans-serif;
|
||||
font-size: 28px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.spacer{
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#head-bar > input{
|
||||
background-color: rgba(255,255,255,0.3);
|
||||
border: 0;
|
||||
padding: 8px;
|
||||
margin: 2px;
|
||||
font-size: 16px;
|
||||
color: white;
|
||||
font-family: 'Muli', sans-serif;
|
||||
min-width: 300px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#head-bar > input:focus{
|
||||
box-shadow: 0px 0px 5px 1px rgba(70,70,70,0.2);
|
||||
}
|
||||
|
||||
#content{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: calc(100% - 93px);
|
||||
flex-direction: column;
|
||||
background-color: rgb(250,250,250);
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
#home-page{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#home-page > input{
|
||||
background-color: #f04f4f;
|
||||
border: 0;
|
||||
padding: 10px;
|
||||
margin: 5px;
|
||||
font-size: 18px;
|
||||
font-family: 'Muli', sans-serif;
|
||||
min-width: 400px;
|
||||
border-radius: 2px;
|
||||
color: white;
|
||||
}
|
||||
#home-page > input:focus{
|
||||
box-shadow: 0px 0px 2px 1px rgba(180,180,180,1);
|
||||
}
|
||||
|
||||
footer{
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: rgb(250,250,250);
|
||||
}
|
||||
footer > a{
|
||||
font-size: 18px;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
color: rgb(100, 100, 100);
|
||||
}
|
||||
|
||||
footer > a:hover{
|
||||
color: rgb(70, 70, 70);
|
||||
}
|
||||
|
||||
.box{
|
||||
background-color: white;
|
||||
padding: 10px;
|
||||
box-shadow: 0px 0px 4px 1px rgba(0,0,0,0.2);
|
||||
display: flex;
|
||||
margin: 10px 0px 10px 0px;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.label{
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
}
|
||||
.label > .label-name{
|
||||
background-color: rgb(120,120,120);
|
||||
color: white;
|
||||
padding: 2px 5px 2px 5px;
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
}
|
||||
|
||||
.label-value{
|
||||
color: white;
|
||||
padding: 2px 5px 2px 5px;
|
||||
border-radius: 0px 2px 2px 0px;
|
||||
}
|
||||
.label > .label-blue{
|
||||
background-color: #3498db;
|
||||
}
|
||||
.label > .label-red{
|
||||
background-color: #e74c3c;
|
||||
}
|
||||
.label > .label-green{
|
||||
background-color: #27ae60;
|
||||
}
|
||||
.label > .label-orange{
|
||||
background-color: #e49517;
|
||||
}
|
||||
.label > .label-purble{
|
||||
background-color: #8a52a0;
|
||||
}
|
||||
|
||||
.download-link-large{
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
text-decoration: none;
|
||||
background-color: #0984e3;
|
||||
padding: 5px 10px 5px 10px;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0px 0px 4px 1px rgba(0,0,0,0.2);
|
||||
margin-top: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
.download-link-large:hover{
|
||||
background-color: #0569b6;
|
||||
}
|
||||
Loading…
Reference in New Issue