refactor/rewritting_the_front_end_with_webpack #20
24
Dockerfile
24
Dockerfile
@ -1,24 +0,0 @@
|
||||
# Author: @ale@ale.manalejandro.com Fixes by: Sergiotarxz. LICENSE: AGPLv3
|
||||
|
||||
FROM debian:sid
|
||||
COPY . /peertube-dl
|
||||
WORKDIR /peertube-dl
|
||||
RUN apt update && apt -y install perl \
|
||||
build-essential \
|
||||
libwww-perl \
|
||||
liburi-encode-perl \
|
||||
libjson-perl \
|
||||
liblwp-protocol-https-perl \
|
||||
libtest-mockobject-perl \
|
||||
libtest-most-perl \
|
||||
libmojolicious-perl \
|
||||
libfile-mimeinfo-perl \
|
||||
cpanminus \
|
||||
duktape-dev \
|
||||
&& apt clean \
|
||||
&& perl Makefile.PL \
|
||||
&& make \
|
||||
&& make test \
|
||||
&& make install
|
||||
|
||||
ENTRYPOINT [ "peertube-dl" ]
|
@ -21,7 +21,8 @@ package MY {
|
||||
my $return = $self->SUPER::top_targets(@_);
|
||||
$return = [ split /\n/, $return ];
|
||||
for my $i ( keys @$return ) {
|
||||
$return->[$i] .= ' install_config' if $return->[$i] =~ /^all :/;
|
||||
$return->[$i] .= ' install_config build_frontend install_frontend'
|
||||
if $return->[$i] =~ /^all :/;
|
||||
}
|
||||
return join "\n", @$return;
|
||||
}
|
||||
@ -42,6 +43,12 @@ THEME = ' . ( $config->{theme} // 'default' ) . "\n";
|
||||
sub postamble {
|
||||
return
|
||||
"\n"
|
||||
. "install_frontend : build_frontend\n"
|
||||
. "\tif [ ! -e lib/Peertube/DL/public/ ];"
|
||||
. " then mkdir -pv lib/Peertube/DL/public/;" . " fi\n"
|
||||
. "\tcp -rfv themes/\${THEME}/public/dist/* lib/Peertube/DL/public/\n"
|
||||
. "build_frontend :\n"
|
||||
. "\tcd themes/\${THEME}/public && yarn install && yarn build\n"
|
||||
. "install_config :\n"
|
||||
. "\tinstall peertube-dl-web.conf bin/peertube-dl-web.conf\n"
|
||||
. "src: src/Makefile\n"
|
||||
|
@ -21,7 +21,7 @@ youtube.com
|
||||
### Localized install with cpanminus.
|
||||
|
||||
```
|
||||
sudo apt install cpanminus ducktape-dev
|
||||
sudo apt install cpanminus ducktape-dev yarn
|
||||
cpanm . --installdeps
|
||||
cpanm .
|
||||
```
|
||||
|
@ -29,6 +29,10 @@ a:hover,a:focus {
|
||||
border: black 1px solid;
|
||||
}
|
||||
|
||||
#modal-video-container.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.video-container-bar {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
@ -245,6 +249,7 @@ h2 {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
background: #eee;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.format-list > div > a:hover {
|
||||
|
File diff suppressed because one or more lines are too long
274
themes/default/public/dist/css/index.css
vendored
Normal file
274
themes/default/public/dist/css/index.css
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
body {
|
||||
height: 99.9%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
a:hover,a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#video {
|
||||
width: 100%;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
#modal-video-container {
|
||||
display: none;
|
||||
background: white;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
border: black 1px solid;
|
||||
}
|
||||
|
||||
#modal-video-container.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.video-container-bar {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
}
|
||||
|
||||
#close-and-reset-video-container {
|
||||
margin-top: 0.25rem;
|
||||
margin-right: 0.25rem;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
#close-and-reset-video-container:hover:#close-and-reset-video-container:focus {
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#download-video-container {
|
||||
margin: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#download-video-container a {
|
||||
display: none;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
width: 100%;
|
||||
background: #0a0;
|
||||
border-radius: 5px;
|
||||
font-size: 30px;
|
||||
color: white;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#download-video-container a.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#download-video-container a embed {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#video-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.application-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#download-form {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#download-form-button {
|
||||
margin-top: 5px;
|
||||
height: 50px;
|
||||
font-size: 1.5rem;
|
||||
background: #fff;
|
||||
color: black;
|
||||
border: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
#modal-loading {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
border: black 1px solid;
|
||||
justify-content: right;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#modal-loading.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#modal-loading embed {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
#poping-notice {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border: black 1px solid;
|
||||
width: 91%;
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 15px;
|
||||
max-height: 95%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#poping-notice.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#poping-notice-container-bar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: 5rem;
|
||||
}
|
||||
|
||||
#close-poping-notice {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: #0f0;
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#close-poping-notice:hover,#close-poping-notice:focus {
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#modal-format-selector {
|
||||
display: none;
|
||||
background: white;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
border: black 1px solid;
|
||||
flex-direction: column;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#modal-format-selector.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#modal-format-selector > h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#modal-format-selector > p {
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
#modal-format-selector .format-list {
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
margin: 2rem;
|
||||
}
|
||||
|
||||
#close-modal-format-selector {
|
||||
margin-top: 0.50rem;
|
||||
margin-right: 0.50rem;
|
||||
border: 1px solid black;
|
||||
background: grey;
|
||||
color: white;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#close-modal-format-selector:hover,#close-modal-format-selector:focus {
|
||||
background: black;
|
||||
}
|
||||
|
||||
.format-list > div {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-auto-columns: 50%;
|
||||
grid-template-areas: "a a";
|
||||
}
|
||||
|
||||
.format-list > div > a {
|
||||
border: 1px solid black;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5rem;
|
||||
padding-right: 5%;
|
||||
padding-left: 5%;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
background: #eee;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.format-list > div > a:hover {
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.format-list > div > a:after {
|
||||
padding-bottom: 100%;
|
||||
display: block;
|
||||
content: "";
|
||||
}
|
||||
|
||||
div.video-formats a {
|
||||
background: #f00;
|
||||
}
|
||||
|
||||
@media (min-width: 668px) {
|
||||
#poping-notice {
|
||||
width: 629px;
|
||||
}
|
||||
}
|
68
themes/default/public/dist/index.html
vendored
Normal file
68
themes/default/public/dist/index.html
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="js/peertube-dl-web.js"></script>
|
||||
<link rel="stylesheet" href="css/index.css"></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body>
|
||||
<div class="application-container">
|
||||
<h2>Peertube-dl Web Application</h2>
|
||||
<form id="download-form">
|
||||
<input class="block" type="text" id="download-form-url" placeholder="Introduce the url you want to download."/>
|
||||
<button class="block" id="download-form-button" >Fetch from api</button>
|
||||
</form>
|
||||
</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">
|
||||
<embed src="img/spinner.svg"/>
|
||||
</div>
|
||||
<div id="modal-video-container">
|
||||
<div class="video-container-bar">
|
||||
<a id="close-and-reset-video-container">x</a>
|
||||
</div>
|
||||
<div id="video-container">
|
||||
<div class="block">
|
||||
<video id="video" controls="controls"></video>
|
||||
</div>
|
||||
<div id="download-video-container" class="block">
|
||||
<a id="download-video-prepare" class="active">Prepare download</a>
|
||||
<a id="download-video-loading"><embed src="img/spinner.svg"/></a>
|
||||
<a id="download-video">Download</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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,
|
||||
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
|
||||
if you distribute this software or use it as an service to users of service or distributees.<p>
|
||||
|
||||
<p>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
|
||||
<a href="https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl/issues">https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl/issues</a>
|
||||
to help this software improve since I find tracking users a pretty bad way to discover bugs and potential good features.</p>
|
||||
|
||||
<p>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.</p>
|
||||
</div>
|
||||
<div id="poping-notice-container-bar">
|
||||
<a id="close-poping-notice" href="#">X</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
13
themes/default/public/package.json
Normal file
13
themes/default/public/package.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "default-theme",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "webpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"webpack": "^5.15.0",
|
||||
"webpack-cli": "^4.3.1"
|
||||
}
|
||||
}
|
106
themes/default/public/src/application.js
Normal file
106
themes/default/public/src/application.js
Normal file
@ -0,0 +1,106 @@
|
||||
"use strict";
|
||||
|
||||
import { PopingNotice } from './view/poping_notice.js';
|
||||
import { DownloadForm } from './view/download_form.js';
|
||||
import { LoadingModal } from './view/loading_modal.js';
|
||||
import { VideoContainer } from './view/video_container.js';
|
||||
import { FormatSelector } from './view/format_selector.js';
|
||||
|
||||
class Application {
|
||||
constructor() {
|
||||
this.poping_notice = new PopingNotice();
|
||||
this.download_form = new DownloadForm(this.onDownloadFormGot.bind(this));
|
||||
this.loading_modal = new LoadingModal();
|
||||
this.video_container = new VideoContainer();
|
||||
this.format_selector = new FormatSelector();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.popingNotice.setVisible(true);
|
||||
}
|
||||
|
||||
onDownloadFormGot(url) {
|
||||
this.dispatchURL(url);
|
||||
}
|
||||
|
||||
dispatchURL(url, format) {
|
||||
this.loadingModal.setVisible(true);
|
||||
let error_str;
|
||||
let success = this.queryAPI(url, format).then( (response) => {
|
||||
if ( response.options !== undefined && response.options.list_formats !== undefined && response.options.list_formats ) {
|
||||
if ( response.formats === undefined
|
||||
|| response.formats.audio_formats === undefined
|
||||
|| response.formats.video_formats === undefined ) {
|
||||
throw 'Format object is not valid.';
|
||||
}
|
||||
this.formatSelector.prepareFormatSelector(
|
||||
response.title, response.description,
|
||||
response.formats.audio_formats, response.formats.video_formats,
|
||||
( id ) => {
|
||||
this.loadingModal.setVisible(true);
|
||||
this.dispatchURL(url, id);
|
||||
});
|
||||
this.formatSelector.setVisible(true);
|
||||
this.loadingModal.setVisible(false);
|
||||
} else {
|
||||
this.videoContainer.onCanPlay(this.onCanPlayVideoContainer.bind(this));
|
||||
this.videoContainer.setURLVideo(response.url);
|
||||
this.videoContainer.setFilename(response.filename);
|
||||
}
|
||||
}).catch( (error) => {
|
||||
error_str = error.toString();
|
||||
this.loadingModal.setVisible(false);
|
||||
let input_url = document.createElement('a');
|
||||
input_url.href = url;
|
||||
input_url.innerText = url;
|
||||
let issues_url = document.createElement('a');
|
||||
issues_url.href = 'https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl/issues';
|
||||
issues_url.innerText = 'here';
|
||||
this.popingNotice.setMessage( [ 'The url ', input_url, ' is not supported, the error was: ', error_str , ' if you think this is an error, report it ', issues_url, '.' ]);
|
||||
this.popingNotice.setVisible(true);
|
||||
});
|
||||
}
|
||||
|
||||
onCanPlayVideoContainer() {
|
||||
this.videoContainer.setVisible(true);
|
||||
this.loadingModal.setVisible(false);
|
||||
}
|
||||
|
||||
async queryAPI(url, format) {
|
||||
let request = { url: url };
|
||||
if (format !== undefined)
|
||||
request.format = format;
|
||||
const response = await fetch('/api', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
cache: 'no-cache',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(request),
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
get formatSelector() {
|
||||
return this.format_selector;
|
||||
}
|
||||
|
||||
get videoContainer() {
|
||||
return this.video_container;
|
||||
}
|
||||
|
||||
get downloadForm() {
|
||||
return this.download_form;
|
||||
}
|
||||
|
||||
get popingNotice() {
|
||||
return this.poping_notice;
|
||||
}
|
||||
|
||||
get loadingModal() {
|
||||
return this.loading_modal;
|
||||
}
|
||||
}
|
||||
|
||||
export { Application };
|
10
themes/default/public/src/index.js
Normal file
10
themes/default/public/src/index.js
Normal file
@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
import { Application } from './application.js';
|
||||
|
||||
window.addEventListener('load', (event) => {
|
||||
let application = new Application();
|
||||
application.init();
|
||||
});
|
||||
|
||||
|
35
themes/default/public/src/view/download_form.js
Normal file
35
themes/default/public/src/view/download_form.js
Normal file
@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
class DownloadForm {
|
||||
constructor(callback) {
|
||||
this.query_selector = '#download-form';
|
||||
this.callback = (event) => {
|
||||
event.preventDefault();
|
||||
callback(this.downloadFormUrl.value);
|
||||
};
|
||||
this.addEventListeners();
|
||||
}
|
||||
|
||||
addEventListeners() {
|
||||
this.downloadFormButton.addEventListener('click', this.callback);
|
||||
this.element.addEventListener('submit', this.callback);
|
||||
}
|
||||
|
||||
get downloadFormButton() {
|
||||
return this.element.querySelector('#download-form-button');
|
||||
}
|
||||
|
||||
get downloadFormUrl() {
|
||||
return this.element.querySelector('#download-form-url');
|
||||
}
|
||||
|
||||
get querySelector() {
|
||||
return this.query_selector;
|
||||
}
|
||||
|
||||
get element() {
|
||||
return document.querySelector(this.querySelector);
|
||||
}
|
||||
}
|
||||
|
||||
export { DownloadForm };
|
87
themes/default/public/src/view/format_selector.js
Normal file
87
themes/default/public/src/view/format_selector.js
Normal file
@ -0,0 +1,87 @@
|
||||
"use strict";
|
||||
|
||||
class FormatSelector {
|
||||
constructor() {
|
||||
this.query_selector = '#modal-format-selector';
|
||||
this.addEventListeners();
|
||||
}
|
||||
|
||||
appendFormat(container, object, is_video, callback) {
|
||||
let a = document.createElement('a');
|
||||
if ( is_video ) {
|
||||
a.innerText = 'Id: ' + object.id + "\n"
|
||||
+ 'Format: ' + object.mimeType + "\n"
|
||||
+ 'QualityLabel: ' + object.qualityLabel + "p\n"
|
||||
+ 'Bitrate: ' + object.bitrate + "\n"
|
||||
+ (
|
||||
( object.audioSampleRate !== undefined ) ?
|
||||
'AudioSampleRate: ' + object.audioSampleRate + ".\n" :
|
||||
"No audio."
|
||||
);
|
||||
} else {
|
||||
a.innerText = 'Id: ' + object.id + "\n"
|
||||
+ 'Format: ' + object.mimeType + "\n"
|
||||
+ 'AudioSampleRate: ' + object.audioSampleRate + "\n"
|
||||
+ 'Bitrate: ' + object.bitrate + ".\n";
|
||||
}
|
||||
a.addEventListener( 'click', (event) => {
|
||||
callback(object.id);
|
||||
});
|
||||
container.appendChild(a);
|
||||
}
|
||||
|
||||
prepareFormatSelector(title, description, audio_formats, video_formats, callback) {
|
||||
this.titleFormatSelector.innerText = title;
|
||||
this.descriptionFormatSelector.innerText = description;
|
||||
this.videoFormats.innerHTML = '';
|
||||
this.audioFormats.innerHTML = '';
|
||||
for ( let x of audio_formats) {
|
||||
this.appendFormat(this.audioFormats, x, false, callback);
|
||||
}
|
||||
for ( let x of video_formats ) {
|
||||
this.appendFormat(this.videoFormats, x, true, callback);
|
||||
}
|
||||
}
|
||||
|
||||
setVisible(option) {
|
||||
if (option) {
|
||||
this.element.classList.add('active');
|
||||
} else {
|
||||
this.element.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
addEventListeners() {
|
||||
this.closeFormatSelector.addEventListener('click', (event) => { this.setVisible(false); });
|
||||
}
|
||||
|
||||
get videoFormats() {
|
||||
return this.element.querySelector('.video-formats');
|
||||
}
|
||||
|
||||
get audioFormats() {
|
||||
return this.element.querySelector('.audio-formats');
|
||||
}
|
||||
|
||||
get titleFormatSelector() {
|
||||
return this.element.querySelector('h2');
|
||||
}
|
||||
|
||||
get descriptionFormatSelector() {
|
||||
return this.element.querySelector('p');
|
||||
}
|
||||
|
||||
get closeFormatSelector() {
|
||||
return this.element.querySelector('#close-modal-format-selector');
|
||||
}
|
||||
|
||||
get element() {
|
||||
return document.querySelector(this.querySelector);
|
||||
}
|
||||
|
||||
get querySelector() {
|
||||
return this.query_selector;
|
||||
}
|
||||
}
|
||||
|
||||
export { FormatSelector };
|
25
themes/default/public/src/view/loading_modal.js
Normal file
25
themes/default/public/src/view/loading_modal.js
Normal file
@ -0,0 +1,25 @@
|
||||
"use strict";
|
||||
|
||||
class LoadingModal {
|
||||
constructor() {
|
||||
this.query_selector = '#modal-loading';
|
||||
}
|
||||
|
||||
setVisible(option) {
|
||||
if (option) {
|
||||
this.element.classList.add('active');
|
||||
} else {
|
||||
this.element.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
get element() {
|
||||
return document.querySelector(this.querySelector);
|
||||
}
|
||||
|
||||
get querySelector() {
|
||||
return this.query_selector;
|
||||
}
|
||||
}
|
||||
|
||||
export { LoadingModal };
|
56
themes/default/public/src/view/poping_notice.js
Normal file
56
themes/default/public/src/view/poping_notice.js
Normal file
@ -0,0 +1,56 @@
|
||||
"use strict";
|
||||
|
||||
class PopingNotice {
|
||||
constructor() {
|
||||
this.query_selector = '#poping-notice';
|
||||
this.closePopingNotice.addEventListener('click', (event) => {
|
||||
this.setVisible(false);
|
||||
});
|
||||
}
|
||||
|
||||
setVisible(option) {
|
||||
if (option) {
|
||||
this.element.classList.add('active');
|
||||
} else {
|
||||
this.element.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
setMessage(message) {
|
||||
if (!message instanceof Array)
|
||||
throw 'Message is not instance of Array.';
|
||||
let p = document.createElement('p');
|
||||
for (let node of message) {
|
||||
if (typeof node === "string"
|
||||
|| node instanceof String) {
|
||||
node = document.createTextNode(node);
|
||||
p.appendChild(node);
|
||||
} else if ( node instanceof Node) {
|
||||
p.appendChild(node);
|
||||
} else {
|
||||
throw ('Node is not a instance of Node nor a String');
|
||||
}
|
||||
}
|
||||
this.popingNoticeContent.innerHTML = '';
|
||||
this.popingNoticeContent.appendChild(p);
|
||||
|
||||
}
|
||||
|
||||
get querySelector() {
|
||||
return this.query_selector;
|
||||
}
|
||||
|
||||
get element() {
|
||||
return document.querySelector(this.querySelector);
|
||||
}
|
||||
|
||||
get popingNoticeContent() {
|
||||
return this.element.querySelector('#poping-notice-content');
|
||||
}
|
||||
|
||||
get closePopingNotice() {
|
||||
return this.element.querySelector('#close-poping-notice');
|
||||
}
|
||||
}
|
||||
|
||||
export { PopingNotice };
|
112
themes/default/public/src/view/video_container.js
Normal file
112
themes/default/public/src/view/video_container.js
Normal file
@ -0,0 +1,112 @@
|
||||
"use strict";
|
||||
|
||||
class VideoContainer {
|
||||
constructor() {
|
||||
this.query_selector = '#modal-video-container';
|
||||
this.addEventListeners();
|
||||
}
|
||||
|
||||
setVisible(option) {
|
||||
if (option) {
|
||||
this.element.classList.add('active');
|
||||
} else {
|
||||
this.element.classList.remove('active');
|
||||
this.downloadVideoPrepare.classList.add('active');
|
||||
this.downloadVideoLoading.classList.remove('active');
|
||||
this.downloadVideo.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
addEventListeners() {
|
||||
this.downloadVideoPrepare.addEventListener('click', this.downloadPrepareHandler.bind(this));
|
||||
this.closeAndResetVideoContainer.addEventListener('click', (event) => {
|
||||
this.setVisible(false);
|
||||
});
|
||||
}
|
||||
|
||||
downloadPrepareHandler(event) {
|
||||
this.downloadVideoPrepare.classList.remove('active');
|
||||
this.downloadVideoLoading.classList.add('active');
|
||||
this.generateBlobVideo(this.URLVideo).then( blob => {
|
||||
this.downloadVideo.href = URL.createObjectURL(blob);
|
||||
this.downloadVideo.download = this.filename;
|
||||
this.downloadVideoLoading.classList.remove('active');
|
||||
this.downloadVideo.classList.add('active');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async generateBlobVideo(url) {
|
||||
const blob = await fetch(url, { mode: 'cors', })
|
||||
.then(res => res.blob())
|
||||
.catch( err => this.generateBlobVideoByProxy(url) );
|
||||
return blob;
|
||||
}
|
||||
|
||||
async generateBlobVideoByProxy(url) {
|
||||
const blob = await fetch( '/proxy_to_get', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
cache: 'no-cache',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({url: url}),
|
||||
}
|
||||
).then(res => res.blob());
|
||||
return blob;
|
||||
}
|
||||
|
||||
onCanPlay(callback) {
|
||||
video.addEventListener('canplay', (event) => {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
setURLVideo(url) {
|
||||
this.url_video = url;
|
||||
video.src = url;
|
||||
}
|
||||
|
||||
setFilename(filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
get closeAndResetVideoContainer() {
|
||||
return this.element.querySelector('#close-and-reset-video-container');
|
||||
}
|
||||
|
||||
get downloadVideo() {
|
||||
return this.element.querySelector('#download-video');
|
||||
}
|
||||
|
||||
get URLVideo() {
|
||||
return this.url_video;
|
||||
}
|
||||
|
||||
get closeAndResetVideoContainer() {
|
||||
return this.element.querySelector('#close-and-reset-video-container');
|
||||
}
|
||||
|
||||
get downloadVideoLoading() {
|
||||
return this.element.querySelector('#download-video-loading');
|
||||
}
|
||||
|
||||
get downloadVideoPrepare() {
|
||||
return this.element.querySelector('#download-video-prepare');
|
||||
}
|
||||
|
||||
get video() {
|
||||
return this.element.querySelector('#video');
|
||||
}
|
||||
|
||||
get element() {
|
||||
return document.querySelector(this.querySelector);
|
||||
}
|
||||
|
||||
get querySelector() {
|
||||
return this.query_selector;
|
||||
}
|
||||
}
|
||||
|
||||
export { VideoContainer };
|
10
themes/default/public/webpack.config.js
Normal file
10
themes/default/public/webpack.config.js
Normal file
@ -0,0 +1,10 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.js',
|
||||
devtool: 'source-map',
|
||||
output: {
|
||||
filename: 'peertube-dl-web.js',
|
||||
path: path.resolve(__dirname, 'dist/js'),
|
||||
},
|
||||
};
|
Loading…
Reference in New Issue
Block a user