From 7d22cfe5c41f3fd47fd34c56a9c03f50e997db4a Mon Sep 17 00:00:00 2001 From: sergiotarxz Date: Wed, 13 Jan 2021 09:13:27 +0100 Subject: [PATCH] Adding the ability to select the format. Issue #3 --- bin/peertube-dl-web | 6 +- lib/Peertube/DL/Downloaders.pm | 76 ++++++++++++---- lib/Peertube/DL/URLHandler.pm | 2 +- lib/Peertube/DL/public/css/index.css | 22 +++-- lib/Peertube/DL/public/index.html | 55 ++++++------ lib/Peertube/DL/public/js/peertube-dl-web.js | 94 ++++++++++++++++---- 6 files changed, 187 insertions(+), 68 deletions(-) diff --git a/bin/peertube-dl-web b/bin/peertube-dl-web index 2903867..9ae5ba6 100755 --- a/bin/peertube-dl-web +++ b/bin/peertube-dl-web @@ -22,10 +22,14 @@ post '/api' => sub { status => 400 ) ); + my $format = $c->req->json->{format}; my $render_returned; eval { $render_returned = $c->render( - json => Peertube::DL::URLHandler::getDownloadDataFromURL($url) ); + json => Peertube::DL::URLHandler::getDownloadDataFromURL( + $url, { ( ( defined $format ) ? ( format => $format ) : () ) }, + ) + ); }; if ($@) { return $c->render( text => $@, status => 500 ); diff --git a/lib/Peertube/DL/Downloaders.pm b/lib/Peertube/DL/Downloaders.pm index 92d684b..f511b76 100644 --- a/lib/Peertube/DL/Downloaders.pm +++ b/lib/Peertube/DL/Downloaders.pm @@ -31,6 +31,14 @@ sub youtube { my $microformat = $ytInitialPlayerResponse->{microformat}{playerMicroformatRenderer}; $ytInitialPlayerResponse = $ytInitialPlayerResponse->{streamingData}; + say Data::Dumper::Dumper [ + scalar @{ $ytInitialPlayerResponse->{adaptiveFormats} } + ? @{ $ytInitialPlayerResponse->{adaptiveFormats} } + : (), + scalar @{ $ytInitialPlayerResponse->{formats} } + ? @{ $ytInitialPlayerResponse->{formats} } + : () + ]; if ( defined $options->{format} ) { my $format = $options->{format}; @@ -116,26 +124,64 @@ sub youtube { ? @{ $ytInitialPlayerResponse->{formats} } : () ]; + my @formats = map { + { + id => $_->{itag}, + 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} } + ? @{ $ytInitialPlayerResponse->{adaptiveFormats} } + : (), + scalar @{ $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 => [ - map { - { - id => $_->{itag}, - mimeType => $_->{mimeType} - } - } ( - scalar @{ $ytInitialPlayerResponse->{adaptiveFormats} } - ? @{ $ytInitialPlayerResponse->{adaptiveFormats} } - : (), - scalar @{ $ytInitialPlayerResponse->{formats} } - ? @{ $ytInitialPlayerResponse->{formats} } - : () - ) - ] + formats => { + video_formats => $video_formats, + audio_formats => $audio_formats, + }, + }; } } diff --git a/lib/Peertube/DL/URLHandler.pm b/lib/Peertube/DL/URLHandler.pm index 115e48b..3715bf9 100644 --- a/lib/Peertube/DL/URLHandler.pm +++ b/lib/Peertube/DL/URLHandler.pm @@ -66,7 +66,7 @@ sub getDownloadDataFromURL { die "No title." unless defined $download_data->{title}; die "No description." unless defined $download_data->{description}; 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 description is $download_data->{description}."; say "The available formats are: @{[Data::Dumper::Dumper $download_data->{formats}]}."; diff --git a/lib/Peertube/DL/public/css/index.css b/lib/Peertube/DL/public/css/index.css index 6b504d5..fa83ef8 100644 --- a/lib/Peertube/DL/public/css/index.css +++ b/lib/Peertube/DL/public/css/index.css @@ -135,7 +135,7 @@ h2 { width: 10%; } -.poping-notice { +#poping-notice { display: none; position: fixed; top: 50%; @@ -150,17 +150,17 @@ h2 { overflow-y: scroll; } -.poping-notice.active { +#poping-notice.active { display: block; } -.poping-notice-container-bar { +#poping-notice-container-bar { display: flex; justify-content: center; font-size: 5rem; } -.close-poping-notice { +#close-poping-notice { width: 150px; height: 150px; align-items: center; @@ -173,7 +173,7 @@ h2 { text-decoration: none; } -.close-poping-notice:hover,.close-poping-notice:focus { +#close-poping-notice:hover,#close-poping-notice:focus { background: black; color: white; } @@ -229,18 +229,22 @@ h2 { .format-list > div { width: 100%; + display: grid; + grid-auto-columns: 50%; + grid-template-areas: "a a"; } .format-list > div > a { border: 1px solid black; - width: 100%; display: flex; align-items: center; justify-content: center; - font-size: 5rem; + font-size: 1.5rem; + padding-right: 5%; + padding-left: 5%; text-decoration: none; color: black; - background: grey; + background: #eee; } .format-list > div > a:hover { @@ -259,7 +263,7 @@ div.video-formats a { } @media (min-width: 668px) { - .poping-notice { + #poping-notice { width: 629px; } } diff --git a/lib/Peertube/DL/public/index.html b/lib/Peertube/DL/public/index.html index 1c6f5c7..4eac01f 100644 --- a/lib/Peertube/DL/public/index.html +++ b/lib/Peertube/DL/public/index.html @@ -12,6 +12,21 @@ + @@ -30,37 +45,23 @@ -
-

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 my gitea 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 - if you distribute this software or use it as an service to users of service or distributees.

+

+

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 my gitea 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 + if you distribute this software or use it as an service to users of service or distributees.

-

I hope that if you find a non supported url which should be supported, a bug, or a feature you would like this webpage to have you file an issue in - https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl/issues - to help this software improve since I find tracking users a pretty bad way to discover bugs and potential good features.

+

I hope that if you find a non supported url which should be supported, a bug, or a feature you would like this webpage to have you file an issue in + https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl/issues + to help this software improve since I find tracking users a pretty bad way to discover bugs and potential good features.

-

This webpage may load third party resources depending on the url you give to it which may put cookies in your browser, you are - 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.

+

This webpage may load third party resources depending on the url you give to it which may put cookies in your browser, you are + 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.

-
- X +
+ X
diff --git a/lib/Peertube/DL/public/js/peertube-dl-web.js b/lib/Peertube/DL/public/js/peertube-dl-web.js index f6a6d31..2b85275 100644 --- a/lib/Peertube/DL/public/js/peertube-dl-web.js +++ b/lib/Peertube/DL/public/js/peertube-dl-web.js @@ -15,26 +15,77 @@ let url; let popingNotice; let popingNoticeContent; let closePopingNotice; +let titleModalFormatSelector; +let descriptionModalFormatSelector; +let modalFormatSelector; +let videoFormats; +let audioFormats; +let closeModalFormatSelector; function downloadFormButtonHandler(event) { event.preventDefault(); modalLoading.classList.add('active'); - getRealURL(downloadFormUrl.value).then( (response) => { - video.src = response.url; - filename = response.filename; - url = response.url; - video.addEventListener('canplay', (event) => { - modalLoading.classList.remove('active'); - modalVideoContainer.style.display = 'block'; - }); + 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; + filename = response.filename; + url = response.url; + video.addEventListener('canplay', (event) => { + modalLoading.classList.remove('active'); + modalVideoContainer.style.display = 'block'; + }); + } + return true; }).catch ( (error) => { + console.log(error); modalLoading.classList.remove('active'); popingNoticeContent.innerHTML = ''; let p = document.createElement('p'); p.appendChild(document.createTextNode('The url ')); let input_url = document.createElement('a'); - input_url.href = downloadFormUrl.value; - input_url.innerText = downloadFormUrl.value; + input_url.href = url; + input_url.innerText = url; p.appendChild(input_url) 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'; @@ -45,6 +96,7 @@ function downloadFormButtonHandler(event) { p.appendChild(document.createTextNode('.')); popingNoticeContent.appendChild(p); popingNotice.classList.add('active'); + return false; }); } @@ -86,7 +138,10 @@ async function generateBlobVideoByProxy(url) { 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', { method: 'POST', mode: 'cors', @@ -94,7 +149,7 @@ async function getRealURL(url) { headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({url: url}), + body: JSON.stringify(request), }); return response.json(); } @@ -118,14 +173,23 @@ window.addEventListener('load', (event) => { downloadVideoPrepare = document.querySelector('#download-video-prepare'); closeAndResetVideoContainer = document.querySelector('#close-and-reset-video-container'); modalLoading = document.querySelector('#modal-loading'); - popingNotice = document.querySelector('.poping-notice'); - popingNoticeContent = document.querySelector('.poping-notice-content'); - closePopingNotice = document.querySelector('.close-poping-notice'); + popingNotice = document.querySelector('#poping-notice'); + popingNoticeContent = document.querySelector('#poping-notice-content'); + 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); downloadVideoPrepare.addEventListener('click', downloadVideoPrepareHandler); downloadForm.addEventListener('submit', downloadFormHandler); closeAndResetVideoContainer.addEventListener('click', closeAndResetVideoContainerHandler); + closeModalFormatSelector.addEventListener('click', (event) => { + modalFormatSelector.classList.remove('active'); + }); closePopingNotice.addEventListener('click', (event) => { popingNotice.classList.remove('active'); });