forked from sergiotarxz/Peertube-dl
parent
a03a7f947c
commit
7d22cfe5c4
@ -22,10 +22,14 @@ post '/api' => sub {
|
|||||||
status => 400
|
status => 400
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
my $format = $c->req->json->{format};
|
||||||
my $render_returned;
|
my $render_returned;
|
||||||
eval {
|
eval {
|
||||||
$render_returned = $c->render(
|
$render_returned = $c->render(
|
||||||
json => Peertube::DL::URLHandler::getDownloadDataFromURL($url) );
|
json => Peertube::DL::URLHandler::getDownloadDataFromURL(
|
||||||
|
$url, { ( ( defined $format ) ? ( format => $format ) : () ) },
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
if ($@) {
|
if ($@) {
|
||||||
return $c->render( text => $@, status => 500 );
|
return $c->render( text => $@, status => 500 );
|
||||||
|
@ -31,6 +31,14 @@ sub youtube {
|
|||||||
my $microformat =
|
my $microformat =
|
||||||
$ytInitialPlayerResponse->{microformat}{playerMicroformatRenderer};
|
$ytInitialPlayerResponse->{microformat}{playerMicroformatRenderer};
|
||||||
$ytInitialPlayerResponse = $ytInitialPlayerResponse->{streamingData};
|
$ytInitialPlayerResponse = $ytInitialPlayerResponse->{streamingData};
|
||||||
|
say Data::Dumper::Dumper [
|
||||||
|
scalar @{ $ytInitialPlayerResponse->{adaptiveFormats} }
|
||||||
|
? @{ $ytInitialPlayerResponse->{adaptiveFormats} }
|
||||||
|
: (),
|
||||||
|
scalar @{ $ytInitialPlayerResponse->{formats} }
|
||||||
|
? @{ $ytInitialPlayerResponse->{formats} }
|
||||||
|
: ()
|
||||||
|
];
|
||||||
|
|
||||||
if ( defined $options->{format} ) {
|
if ( defined $options->{format} ) {
|
||||||
my $format = $options->{format};
|
my $format = $options->{format};
|
||||||
@ -116,16 +124,30 @@ sub youtube {
|
|||||||
? @{ $ytInitialPlayerResponse->{formats} }
|
? @{ $ytInitialPlayerResponse->{formats} }
|
||||||
: ()
|
: ()
|
||||||
];
|
];
|
||||||
|
my @formats = map {
|
||||||
return {
|
|
||||||
options => { list_formats => 1 },
|
|
||||||
title => $microformat->{title}{simpleText},
|
|
||||||
description => $microformat->{description}{simpleText},
|
|
||||||
formats => [
|
|
||||||
map {
|
|
||||||
{
|
{
|
||||||
id => $_->{itag},
|
id => $_->{itag},
|
||||||
mimeType => $_->{mimeType}
|
mimeType => $_->{mimeType},
|
||||||
|
(
|
||||||
|
( defined $_->{averageBitrate} && defined $_->{bitrate} )
|
||||||
|
? ( bitrate => $_->{averageBitrate} // $_->{bitrate} )
|
||||||
|
: ()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
( defined $_->{qualityLabel} )
|
||||||
|
? ( qualityLabel => int( $_->{qualityLabel} ) )
|
||||||
|
: ()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
( defined $_->{audioSampleRate} )
|
||||||
|
? ( audioSampleRate => $_->{audioSampleRate} )
|
||||||
|
: ()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
( defined $_->{quality} )
|
||||||
|
? ( quality => $_->{quality} )
|
||||||
|
: ()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
} (
|
} (
|
||||||
scalar @{ $ytInitialPlayerResponse->{adaptiveFormats} }
|
scalar @{ $ytInitialPlayerResponse->{adaptiveFormats} }
|
||||||
@ -134,8 +156,32 @@ sub youtube {
|
|||||||
scalar @{ $ytInitialPlayerResponse->{formats} }
|
scalar @{ $ytInitialPlayerResponse->{formats} }
|
||||||
? @{ $ytInitialPlayerResponse->{formats} }
|
? @{ $ytInitialPlayerResponse->{formats} }
|
||||||
: ()
|
: ()
|
||||||
)
|
);
|
||||||
]
|
my $video_formats = [
|
||||||
|
sort {
|
||||||
|
$b->{qualityLabel} <=> $a->{qualityLabel}
|
||||||
|
|| $b->{bitrate} <=> $a->{bitrate}
|
||||||
|
} grep { defined $_->{qualityLabel} } @formats
|
||||||
|
];
|
||||||
|
my $audio_formats = [
|
||||||
|
sort {
|
||||||
|
$a->{audioSampleRate} <=> $b->{audioSampleRate}
|
||||||
|
|| $b->{bitrate} <=> $a->{bitrate}
|
||||||
|
} grep {
|
||||||
|
defined $_->{audioSampleRate}
|
||||||
|
&& $_->{mimeType} =~ /webm;/
|
||||||
|
} @formats
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
options => { list_formats => 1 },
|
||||||
|
title => $microformat->{title}{simpleText},
|
||||||
|
description => $microformat->{description}{simpleText},
|
||||||
|
formats => {
|
||||||
|
video_formats => $video_formats,
|
||||||
|
audio_formats => $audio_formats,
|
||||||
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ sub getDownloadDataFromURL {
|
|||||||
die "No title." unless defined $download_data->{title};
|
die "No title." unless defined $download_data->{title};
|
||||||
die "No description." unless defined $download_data->{description};
|
die "No description." unless defined $download_data->{description};
|
||||||
die "No formats available." unless defined $download_data->{formats};
|
die "No formats available." unless defined $download_data->{formats};
|
||||||
die "Formats is not an arrayref." unless ref $download_data->{formats} eq 'ARRAY';
|
die "Formats is not a hash." unless ref $download_data->{formats} eq 'HASH';
|
||||||
say "The video title is $download_data->{title}.";
|
say "The video title is $download_data->{title}.";
|
||||||
say "The video description is $download_data->{description}.";
|
say "The video description is $download_data->{description}.";
|
||||||
say "The available formats are: @{[Data::Dumper::Dumper $download_data->{formats}]}.";
|
say "The available formats are: @{[Data::Dumper::Dumper $download_data->{formats}]}.";
|
||||||
|
@ -135,7 +135,7 @@ h2 {
|
|||||||
width: 10%;
|
width: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.poping-notice {
|
#poping-notice {
|
||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@ -150,17 +150,17 @@ h2 {
|
|||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
.poping-notice.active {
|
#poping-notice.active {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.poping-notice-container-bar {
|
#poping-notice-container-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 5rem;
|
font-size: 5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-poping-notice {
|
#close-poping-notice {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
height: 150px;
|
height: 150px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -173,7 +173,7 @@ h2 {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-poping-notice:hover,.close-poping-notice:focus {
|
#close-poping-notice:hover,#close-poping-notice:focus {
|
||||||
background: black;
|
background: black;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
@ -229,18 +229,22 @@ h2 {
|
|||||||
|
|
||||||
.format-list > div {
|
.format-list > div {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-auto-columns: 50%;
|
||||||
|
grid-template-areas: "a a";
|
||||||
}
|
}
|
||||||
|
|
||||||
.format-list > div > a {
|
.format-list > div > a {
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 5rem;
|
font-size: 1.5rem;
|
||||||
|
padding-right: 5%;
|
||||||
|
padding-left: 5%;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: black;
|
color: black;
|
||||||
background: grey;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.format-list > div > a:hover {
|
.format-list > div > a:hover {
|
||||||
@ -259,7 +263,7 @@ div.video-formats a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 668px) {
|
@media (min-width: 668px) {
|
||||||
.poping-notice {
|
#poping-notice {
|
||||||
width: 629px;
|
width: 629px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,21 @@
|
|||||||
<button class="block" id="download-form-button" >Fetch from api</button>
|
<button class="block" id="download-form-button" >Fetch from api</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="modal-format-selector">
|
||||||
|
<div class="video-container-bar">
|
||||||
|
<a id="close-modal-format-selector">x</a>
|
||||||
|
</div>
|
||||||
|
<h2>Example video</h2>
|
||||||
|
<p>Example description</p>
|
||||||
|
<div class="format-list">
|
||||||
|
<h3>Video Formats.</h3>
|
||||||
|
<div class="video-formats">
|
||||||
|
</div>
|
||||||
|
<h3>Audio Formats.</h3>
|
||||||
|
<div class="audio-formats">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="modal-loading">
|
<div id="modal-loading">
|
||||||
<embed src="img/spinner.svg"/>
|
<embed src="img/spinner.svg"/>
|
||||||
</div>
|
</div>
|
||||||
@ -30,22 +45,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="modal-format-selector" class="active">
|
|
||||||
<div class="video-container-bar">
|
|
||||||
<a id="close-modal-format-selector">x</a>
|
|
||||||
</div>
|
|
||||||
<h2>Example video</h2>
|
|
||||||
<p>Example description</p>
|
|
||||||
<div class="format-list">
|
|
||||||
<div class="video-formats">
|
|
||||||
<a href="18">18</a>
|
|
||||||
</div>
|
|
||||||
<div class="audio-formats">
|
|
||||||
<a href="251">251</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="poping-notice">
|
<div id="poping-notice">
|
||||||
|
<div id="poping-notice-content">
|
||||||
<p>This webpage is free as in freedom software, it is offered to you with the hope it will be useful, but without any warranty,
|
<p>This webpage is free as in freedom software, it is offered to you with the hope it will be useful, but without any warranty,
|
||||||
you can find the source code at <a href="https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl">my gitea</a> with docs to setup your own
|
you can find the source code at <a href="https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl">my gitea</a> with docs to setup your own
|
||||||
webpage like this, this software is licensed under the AGPLv3 license which means you MUST convey the source code in a human readable form
|
webpage like this, this software is licensed under the AGPLv3 license which means you MUST convey the source code in a human readable form
|
||||||
@ -59,8 +60,8 @@
|
|||||||
encouraged to frecuently delete your browser cookies to avoid those third parties tracking you on internet, Firefox offers you an
|
encouraged to frecuently delete your browser cookies to avoid those third parties tracking you on internet, Firefox offers you an
|
||||||
option to delete cookies as soon as you close the browser which may be a good idea to enable in the orwellian internet of today.</p>
|
option to delete cookies as soon as you close the browser which may be a good idea to enable in the orwellian internet of today.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="poping-notice-container-bar">
|
<div id="poping-notice-container-bar">
|
||||||
<a class="close-poping-notice" href="#">X</a>
|
<a id="close-poping-notice" href="#">X</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
@ -15,11 +15,59 @@ let url;
|
|||||||
let popingNotice;
|
let popingNotice;
|
||||||
let popingNoticeContent;
|
let popingNoticeContent;
|
||||||
let closePopingNotice;
|
let closePopingNotice;
|
||||||
|
let titleModalFormatSelector;
|
||||||
|
let descriptionModalFormatSelector;
|
||||||
|
let modalFormatSelector;
|
||||||
|
let videoFormats;
|
||||||
|
let audioFormats;
|
||||||
|
let closeModalFormatSelector;
|
||||||
|
|
||||||
function downloadFormButtonHandler(event) {
|
function downloadFormButtonHandler(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
modalLoading.classList.add('active');
|
modalLoading.classList.add('active');
|
||||||
getRealURL(downloadFormUrl.value).then( (response) => {
|
askForURL(downloadFormUrl.value);
|
||||||
|
}
|
||||||
|
function askForURL(url, format) {
|
||||||
|
getRealURL(url, format).then( (response) => {
|
||||||
|
if ( response.options !== undefined && response.options.list_formats !== undefined && response.options.list_formats ) {
|
||||||
|
titleModalFormatSelector.innerText = response.title;
|
||||||
|
descriptionModalFormatSelector.innerText = response.description;
|
||||||
|
videoFormats.innerHTML = '';
|
||||||
|
audioFormats.innerHTML = '';
|
||||||
|
for ( let x of response.formats.audio_formats) {
|
||||||
|
let a = document.createElement('a');
|
||||||
|
a.innerText = 'Id: ' + x.id + "\n"
|
||||||
|
+ 'Format: ' + x.mimeType + "\n"
|
||||||
|
+ 'AudioSampleRate: ' + x.audioSampleRate + "\n"
|
||||||
|
+ 'Bitrate: ' + x.bitrate + ".\n";
|
||||||
|
a.addEventListener( 'click', (event) => {
|
||||||
|
modalLoading.classList.add('active');
|
||||||
|
askForURL(url, x.id );
|
||||||
|
});
|
||||||
|
audioFormats.appendChild(a);
|
||||||
|
modalLoading.classList.remove('active');
|
||||||
|
modalFormatSelector.classList.add('active');
|
||||||
|
}
|
||||||
|
for ( let x of response.formats.video_formats ) {
|
||||||
|
let a = document.createElement('a');
|
||||||
|
a.innerText = 'Id: ' + x.id + "\n"
|
||||||
|
+ 'Format: ' + x.mimeType + "\n"
|
||||||
|
+ 'QualityLabel: ' + x.qualityLabel + "p\n"
|
||||||
|
+ 'Bitrate: ' + x.bitrate + "\n"
|
||||||
|
+ (
|
||||||
|
( x.audioSampleRate !== undefined ) ?
|
||||||
|
'AudioSampleRate: ' + x.audioSampleRate + ".\n" :
|
||||||
|
"No audio."
|
||||||
|
);
|
||||||
|
a.addEventListener( 'click', (event) => {
|
||||||
|
modalLoading.classList.add('active');
|
||||||
|
askForURL(url, x.id );
|
||||||
|
});
|
||||||
|
videoFormats.appendChild(a);
|
||||||
|
modalLoading.classList.remove('active');
|
||||||
|
modalFormatSelector.classList.add('active');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
video.src = response.url;
|
video.src = response.url;
|
||||||
filename = response.filename;
|
filename = response.filename;
|
||||||
url = response.url;
|
url = response.url;
|
||||||
@ -27,14 +75,17 @@ function downloadFormButtonHandler(event) {
|
|||||||
modalLoading.classList.remove('active');
|
modalLoading.classList.remove('active');
|
||||||
modalVideoContainer.style.display = 'block';
|
modalVideoContainer.style.display = 'block';
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}).catch ( (error) => {
|
}).catch ( (error) => {
|
||||||
|
console.log(error);
|
||||||
modalLoading.classList.remove('active');
|
modalLoading.classList.remove('active');
|
||||||
popingNoticeContent.innerHTML = '';
|
popingNoticeContent.innerHTML = '';
|
||||||
let p = document.createElement('p');
|
let p = document.createElement('p');
|
||||||
p.appendChild(document.createTextNode('The url '));
|
p.appendChild(document.createTextNode('The url '));
|
||||||
let input_url = document.createElement('a');
|
let input_url = document.createElement('a');
|
||||||
input_url.href = downloadFormUrl.value;
|
input_url.href = url;
|
||||||
input_url.innerText = downloadFormUrl.value;
|
input_url.innerText = url;
|
||||||
p.appendChild(input_url)
|
p.appendChild(input_url)
|
||||||
p.appendChild(document.createTextNode(' is not supported, if you think this is an error, report it '));
|
p.appendChild(document.createTextNode(' is not supported, if you think this is an error, report it '));
|
||||||
let issues_url = 'https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl/issues';
|
let issues_url = 'https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl/issues';
|
||||||
@ -45,6 +96,7 @@ function downloadFormButtonHandler(event) {
|
|||||||
p.appendChild(document.createTextNode('.'));
|
p.appendChild(document.createTextNode('.'));
|
||||||
popingNoticeContent.appendChild(p);
|
popingNoticeContent.appendChild(p);
|
||||||
popingNotice.classList.add('active');
|
popingNotice.classList.add('active');
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +138,10 @@ async function generateBlobVideoByProxy(url) {
|
|||||||
return blob;
|
return blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getRealURL(url) {
|
async function getRealURL(url, format) {
|
||||||
|
let request = { url: url };
|
||||||
|
if (format !== undefined)
|
||||||
|
request.format = format;
|
||||||
const response = await fetch('/api', {
|
const response = await fetch('/api', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
mode: 'cors',
|
mode: 'cors',
|
||||||
@ -94,7 +149,7 @@ async function getRealURL(url) {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({url: url}),
|
body: JSON.stringify(request),
|
||||||
});
|
});
|
||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
@ -118,14 +173,23 @@ window.addEventListener('load', (event) => {
|
|||||||
downloadVideoPrepare = document.querySelector('#download-video-prepare');
|
downloadVideoPrepare = document.querySelector('#download-video-prepare');
|
||||||
closeAndResetVideoContainer = document.querySelector('#close-and-reset-video-container');
|
closeAndResetVideoContainer = document.querySelector('#close-and-reset-video-container');
|
||||||
modalLoading = document.querySelector('#modal-loading');
|
modalLoading = document.querySelector('#modal-loading');
|
||||||
popingNotice = document.querySelector('.poping-notice');
|
popingNotice = document.querySelector('#poping-notice');
|
||||||
popingNoticeContent = document.querySelector('.poping-notice-content');
|
popingNoticeContent = document.querySelector('#poping-notice-content');
|
||||||
closePopingNotice = document.querySelector('.close-poping-notice');
|
closePopingNotice = document.querySelector('#close-poping-notice');
|
||||||
|
titleModalFormatSelector = document.querySelector('#modal-format-selector h2');
|
||||||
|
descriptionModalFormatSelector = document.querySelector('#modal-format-selector p');
|
||||||
|
modalFormatSelector = document.querySelector('#modal-format-selector');
|
||||||
|
videoFormats = document.querySelector('#modal-format-selector .video-formats');
|
||||||
|
audioFormats = document.querySelector('#modal-format-selector .audio-formats');
|
||||||
|
closeModalFormatSelector = document.querySelector('#close-modal-format-selector');
|
||||||
|
|
||||||
downloadFormButton.addEventListener('click', downloadFormButtonHandler);
|
downloadFormButton.addEventListener('click', downloadFormButtonHandler);
|
||||||
downloadVideoPrepare.addEventListener('click', downloadVideoPrepareHandler);
|
downloadVideoPrepare.addEventListener('click', downloadVideoPrepareHandler);
|
||||||
downloadForm.addEventListener('submit', downloadFormHandler);
|
downloadForm.addEventListener('submit', downloadFormHandler);
|
||||||
closeAndResetVideoContainer.addEventListener('click', closeAndResetVideoContainerHandler);
|
closeAndResetVideoContainer.addEventListener('click', closeAndResetVideoContainerHandler);
|
||||||
|
closeModalFormatSelector.addEventListener('click', (event) => {
|
||||||
|
modalFormatSelector.classList.remove('active');
|
||||||
|
});
|
||||||
closePopingNotice.addEventListener('click', (event) => {
|
closePopingNotice.addEventListener('click', (event) => {
|
||||||
popingNotice.classList.remove('active');
|
popingNotice.classList.remove('active');
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user