Add support for subtitles, extraction

pull/14/head
aandrew-me 4 years ago
parent 10e8c1c847
commit f3e5792f43

@ -35,7 +35,7 @@ input[type="text"]{
#back{
text-decoration: none;
padding:8px;
border-radius: 8px;
border-radius: 10px;
background-color: rgb(51, 177, 219);
color:white;
position: absolute;
@ -44,6 +44,19 @@ input[type="text"]{
font-size: large;
cursor: pointer;
}
#restart{
text-decoration: none;
padding:8px;
border-radius: 10px;
background-color: rgb(210 69 27);
color:white;
position: absolute;
top:15px;
right:120px;
font-size: large;
cursor: pointer;
}
a{
color:rgb(34, 136, 199);
cursor: pointer;
@ -52,6 +65,9 @@ a{
input[type="checkbox"]{
width:20px;
height:20px;
position: relative;
left:5px;
top: 5px;
}
#selectLocation{

@ -219,6 +219,14 @@ label {
display: none;
}
input[type="checkbox"]{
width:20px;
height:20px;
position: relative;
left:5px;
top:4px;
}
.submitBtn {
padding: 15px;
border-radius: 10px;
@ -320,8 +328,30 @@ svg {
#savedMsg {
cursor: pointer;
}
button{
outline:none;
}
#extractBtn{
color: white;
background-color: rgb(80, 128, 230);
border: none;
border-bottom: 4px solid rgb(44, 78, 180);
position: relative;
padding: 15px;
border-radius: 10px;
cursor: pointer;
margin: 8px;
font-size: large;
}
#advancedToggle {
#extractBtn:active{
top: 4px;
margin-bottom: 12px;
border: none;
}
.advancedToggle {
color: white;
background-color: rgb(231, 80, 80);
border: none;
@ -334,9 +364,9 @@ svg {
font-size: large;
}
#advancedToggle:active {
.advancedToggle:active {
top: 4px;
margin-bottom: 4px;
margin-bottom: 12px;
border: none;
}

@ -2,7 +2,7 @@
<html lang="en">
<head>
<header ></header>
<header></header>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@ -12,7 +12,7 @@
<script src="../src/index.js" defer></script>
<!-- Translating -->
<script>window.i18n = new(require('../translations/i18n'));</script>
<script>window.i18n = new (require('../translations/i18n'));</script>
</head>
@ -54,7 +54,7 @@
<button id="pasteUrl" class="submitBtn">Click to paste video URL or ID [Ctrl + V]</button>
<div id="loadingWrapper">
<span id="processing">Processing </span>
<span id="processing">Loading </span>
<svg version="1.1" id="L4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<circle fill="rgb(84, 171, 222)" stroke="none" cx="6" cy="50" r="6">
@ -85,30 +85,58 @@
<br>
<input type="hidden" name="url" class="url" id="url">
<button class="submitBtn" id="videoDownload">Download</button>
<button id="advancedToggle" onClick ="advancedToggle()">More options</button>
<button id="advancedVideoToggle" class="advancedToggle" onClick="advancedToggle()">More options</button>
</div>
<div id="audioList">
<label>Select Format </label>
<select id="audioFormatSelect">
</select>
<br>
<input type="hidden" name="url" class="url">
<button class="submitBtn" id="audioDownload">Download</button>
<button id="advancedToggle" onClick ="advancedToggle()">Advanced</button>
<div id="audioPresent">
<label>Select Format </label>
<select id="audioFormatSelect">
</select>
<br>
<input type="hidden" name="url" class="url">
<button class="submitBtn" id="audioDownload">Download</button>
<button id="advancedAudioToggle" class="advancedToggle" onClick="advancedToggle()">More options</button>
</div>
</div>
<div id="advanced">
<p id="rangeText">Download particular time-range</p>
<label id="start">Start</label>
<input type="text" id="startTime" class="time" placeholder="00:00" title="If kept empty, it will start from the beginning">
<input type="text" id="startTime" class="time" placeholder="00:00"
title="If kept empty, it will start from the beginning">
:
<input type="text" id="endTime" class="time" placeholder="10:00" title="If kept empty, it will be downloaded to the end">
<input type="text" id="endTime" class="time" placeholder="10:00"
title="If kept empty, it will be downloaded to the end">
<label id="end">End</label>
<br><br>
<h3>Subtitles</h3>
<span>Download subtitles if available</span>
<input id="subChecked" type="checkbox">
<br><br>
<span>Download auto generated subtitles</span>
<input id="autoSubChecked" type="checkbox">
</div>
<!-- Extraction options start -->
<h2>Extract Audio from Video</h2>
<label>Select Format </label>
<select id="extractSelection">
<option value="mp3">Mp3</option>
<option value="aac">Aac</option>
<option value="m4a">M4a</option>
<option value="opus">Opus</option>
<option value="wav">Wav</option>
<option value="alac">Alac</option>
<option value="flac">Flac</option>
<option value="vorbis">Vorbis</option>
</select>
<button id="extractBtn">Extract audio</button>
<!-- Extraction options end -->
</div>
<br><br><br><br>

@ -13,6 +13,9 @@
<body>
<a id="back">Homepage</a>
<a id="restart" onclick="restartApp()">Restart app</a>
<h1 id="preferences">Preferences</h1>
<br><br>
<strong id="dlText">Download location</strong>
@ -30,7 +33,7 @@
<br><br>
<label id="selectLn">Select Language</label>
<label id="selectLn">Select Language (Requires reload)</label>
<select id="select" onchange="changeLanguage()">
<option value="en">English</option>
<option value="ru">Русский</option>
@ -45,6 +48,10 @@
return document.getElementById(id)
}
function restartApp(){
ipcRenderer.send("restart")
}
getId("back").addEventListener("click", () => {
ipcRenderer.send("close-secondary")
})

@ -44,6 +44,11 @@ app.whenReady().then(() => {
}
});
ipcMain.on("restart", () => {
app.relaunch();
app.exit();
})
ipcMain.on("get-version", () => {
const version = app.getVersion();
secondaryWindow.webContents.send("version", version);
@ -61,7 +66,7 @@ ipcMain.on("load-page", (event, file) => {
});
secondaryWindow.loadFile(file);
// secondaryWindow.setMenu(null);
secondaryWindow.maximize();
// secondaryWindow.maximize();
secondaryWindow.show();
});

@ -17,6 +17,7 @@ getId("menuIcon").addEventListener("click", (event) => {
let opacity = 1;
const fade = setInterval(() => {
if (count >= 10) {
getId("menu").style.display = "none"
clearInterval(fade);
} else {
opacity -= 0.1;
@ -110,14 +111,6 @@ if (storageTheme == "dark") {
toggle();
}
////
function clickAnimation(id) {
getId(id).style.animationName = "clickAnimation";
setTimeout(() => {
getId(id).style.animationName = "";
}, 500);
}
let advancedHidden = true;
function advancedToggle() {

@ -1,11 +1,10 @@
const cp = require("child_process");
const os = require("os");
let ffmpeg;
if (os.platform() === "win32"){
ffmpeg = __dirname + "\\..\\ffmpeg.exe"
}
else{
ffmpeg = __dirname + "/../ffmpeg"
if (os.platform() === "win32") {
ffmpeg = __dirname + "\\..\\ffmpeg.exe";
} else {
ffmpeg = __dirname + "/../ffmpeg";
}
const fs = require("fs");
@ -18,18 +17,18 @@ const { default: YTDlpWrap } = require("yt-dlp-wrap-extended");
const homedir = os.homedir();
const appdir = path.join(homedir, "Downloads");
const hiddenDir = path.join(homedir, ".ytDownloader");
const i18n = new(require('../translations/i18n'))
const i18n = new (require("../translations/i18n"))();
fs.mkdir(hiddenDir, { recursive: true }, () => {});
// Download directory
let downloadDir = "";
// Global variables
let title, onlyvideo, id, thumbnail, ytdlp, duration;
let title, onlyvideo, id, thumbnail, ytdlp, duration, extractFormat;
let rangeCmd = "";
let subs = ""
let autoSubs = ""
let rangeOption = "--download-sections";
let willBeSaved = true;
@ -84,12 +83,13 @@ cp.exec("yt-dlp --version", (error, stdout, stderr) => {
if (error) {
getId("popupBox").style.display = "block";
process.on("uncaughtException", (reason, promise) => {
document.querySelector("#popupBox p").textContent =
i18n.__("Failed to download yt-dlp. Please check your connection and try again");
document.querySelector("#popupBox p").textContent = i18n.__(
"Failed to download yt-dlp. Please check your network and try again"
);
getId("popupSvg").style.display = "none";
getId(
"popup"
).innerHTML += `<button id="tryBtn">${i18n.__("Try again")}</button>`;
getId("popup").innerHTML += `<button id="tryBtn">${i18n.__(
"Try again"
)}</button>`;
console.log("Failed to download yt-dlp");
getId("tryBtn").addEventListener("click", () => {
@ -154,6 +154,7 @@ getId("pasteUrl").addEventListener("click", () => {
// Getting video info
async function getInfo(url) {
let audioIsPresent = false;
downloadPathSelection();
getId("videoFormatSelect").innerHTML = "";
getId("audioFormatSelect").innerHTML = "";
@ -193,12 +194,13 @@ async function getInfo(url) {
let audioSize = 0;
// Getting approx size of audio file
// Getting approx size of audio file and checking if audio is present
for (let format of formats) {
if (
format.audio_ext !== "none" ||
(format.acodec !== "none" && format.video_ext === "none")
) {
audioIsPresent = true;
onlyvideo = true;
audioSize =
Number(format.filesize || format.filesize_approx) /
@ -266,7 +268,8 @@ async function getInfo(url) {
"<option value='" +
format_id +
"'>" +
i18n.__("Quality") + ": " +
i18n.__("Quality") +
": " +
(format.format_note || i18n.__("Unknown quality")) +
" | " +
audio_ext +
@ -299,16 +302,25 @@ async function getInfo(url) {
" | " +
format.ext +
" | " +
size + " " +
size +
" " +
i18n.__("MB") +
"</option>";
getId("videoFormatSelect").innerHTML += element;
}
// When there is no audio
if (audioIsPresent === false) {
getId("audioPresent").style.display = "none";
} else {
getId("audioPresent").style.display = "block";
}
}
} else {
getId("loadingWrapper").style.display = "none";
getId("incorrectMsg").textContent =
i18n.__("Some error has occured. Check your connection and use correct URL");
getId("incorrectMsg").textContent = i18n.__(
"Some error has occured. Check your connection and use correct URL"
);
}
});
}
@ -316,17 +328,21 @@ async function getInfo(url) {
// Video download event
getId("videoDownload").addEventListener("click", (event) => {
getId("hidden").style.display = "none";
clickAnimation("videoDownload");
download("video");
});
// Audio download event
getId("audioDownload").addEventListener("click", (event) => {
getId("hidden").style.display = "none";
clickAnimation("audioDownload");
download("audio");
});
getId("extractBtn").addEventListener("click", () => {
extractFormat = getId("extractSelection").value;
getId("hidden").style.display = "none";
download("extract");
});
// Restore previous uncompleted downloads
// function restorePrevious() {
@ -399,7 +415,23 @@ function manageAdvanced(duration) {
rangeOption = "--download-sections";
} else {
rangeOption = "";
rangeCmd = ""
rangeCmd = "";
}
// If subtitles are checked
if (getId("subChecked").checked){
subs = "--write-subs"
}
else{
subs = ""
}
// If autosubs are checked
if (getId("autoSubChecked").checked){
autoSubs = "--write-auto-subs"
}
else{
subs = ""
}
console.log("Range option: " + rangeOption);
@ -420,7 +452,7 @@ function download(type) {
if (type === "video") {
format_id = getId("videoFormatSelect").value.split("|")[0];
ext = getId("videoFormatSelect").value.split("|")[1];
} else {
} else if (type === "audio") {
format_id = getId("audioFormatSelect").value.split("|")[0];
if (getId("audioFormatSelect").value.split("|")[1] === "webm") {
ext = "opus";
@ -486,9 +518,7 @@ function download(type) {
}
filename += letter;
}
filename =
filename + Math.random().toFixed(3).toString().slice(2) + `.${ext}`;
console.log(path.join(downloadDir, filename));
filename = filename + Math.random().toFixed(3).toString().slice(2);
let audioFormat;
@ -501,7 +531,6 @@ function download(type) {
let controller = new AbortController();
console.log(rangeOption + " " + rangeCmd);
if (type === "video" && onlyvideo) {
// If video has no sound, audio needs to be downloaded
console.log("Downloading both video and audio");
@ -514,16 +543,18 @@ function download(type) {
"-f",
`${format_id}+${audioFormat}`,
"-o",
`${path.join(downloadDir, filename)}`,
`${path.join(downloadDir, filename + `.${ext}`)}`,
"--ffmpeg-location",
ffmpeg,
subs,
autoSubs
],
{ shell: true, detached: false },
controller.signal
);
// If downloading only audio or video with audio
} else {
} else if (type === "audio") {
downloadProcess = ytdlp.exec(
[
url,
@ -532,7 +563,24 @@ function download(type) {
"-f",
format_id,
"-o",
`${path.join(downloadDir, filename)}`,
`${path.join(downloadDir, filename + `.${ext}`)}`,
"--ffmpeg-location",
ffmpeg,
subs,
autoSubs
],
{ shell: true, detached: false },
controller.signal
);
} else if (type === "extract") {
downloadProcess = ytdlp.exec(
[
url,
"-x",
"--audio-format",
extractFormat,
"-o",
`${path.join(downloadDir, filename + `.${extractFormat}`)}`,
"--ffmpeg-location",
ffmpeg,
],
@ -547,12 +595,17 @@ function download(type) {
controller.abort();
});
downloadProcess
.on("progress", (progress) => {
getId(randomId + "prog").textContent = `${i18n.__("Progress")}: ${
progress.percent
}% ${i18n.__("Speed")}: ${progress.currentSpeed || 0}`;
if (progress == 100){
getId(randomId + "prog").textContent = i18n.__("Processing")
}
else{
getId(randomId + "prog").textContent = `${i18n.__("Progress")}: ${
progress.percent
}% ${i18n.__("Speed")}: ${progress.currentSpeed || 0}`;
}
const items = JSON.parse(localStorage.getItem("itemList"));
// Clearing item from localstorage
@ -579,12 +632,28 @@ function download(type) {
}
localStorage.setItem("itemList", JSON.stringify(items));
afterSave(downloadDir, filename, randomId + "prog");
if (type === "extract") {
console.log(path.join(downloadDir, filename + `.${extractFormat}`));
afterSave(
downloadDir,
filename + `.${extractFormat}`,
randomId + "prog"
);
} else {
console.log(path.join(downloadDir, filename + `.${ext}`));
afterSave(
downloadDir,
filename + `.${ext}`,
randomId + "prog"
);
}
}
})
.on("error", (error) => {
getId(randomId + "prog").textContent =
i18n.__("Some error has occured. Hover to see details");
getId(randomId + "prog").textContent = i18n.__(
"Some error has occured. Hover to see details"
);
getId(randomId + "prog").title = error.message;
console.log(error.message);
});
@ -616,15 +685,17 @@ function afterSave(location, filename, progressId) {
body: i18n.__("File saved successfully"),
icon: "../assets/images/icon.png",
});
let finalLocation = location
let finalFilename = filename
if (os.platform() === "win32"){
finalLocation = location.split(path.sep).join("\\\\")
finalFilename = filename.split(path.sep).join("\\\\")
let finalLocation = location;
let finalFilename = filename;
if (os.platform() === "win32") {
finalLocation = location.split(path.sep).join("\\\\");
finalFilename = filename.split(path.sep).join("\\\\");
}
getId(
progressId
).innerHTML = `<b onClick="showItem('${finalLocation}', '${finalFilename}')">${i18n.__("File saved. Click to Open")}</b>`;
).innerHTML = `<b onClick="showItem('${finalLocation}', '${finalFilename}')">${i18n.__(
"File saved. Click to Open"
)}</b>`;
}
function showItem(location, filename) {

@ -15,7 +15,8 @@ querySelector("#videoList label").textContent = i18n.__("Select Format ")
querySelector("#audioList label").textContent = i18n.__("Select Format ")
getId("videoDownload").textContent = i18n.__("Download")
getId("audioDownload").textContent = i18n.__("Download")
getId("advancedToggle").textContent = i18n.__("More options")
getId("advancedVideoToggle").textContent = i18n.__("More options")
getId("advancedAudioToggle").textContent = i18n.__("More options")
getId("rangeText").textContent= i18n.__("Download particular time-range")
getId("startTime").title = i18n.__("If kept empty, it will start from the beginning")
getId("endTime").title = i18n.__("If kept empty, it will be downloaded to the end")

@ -12,6 +12,7 @@ getId("back").textContent = i18n.__("Homepage")
getId("dlText").textContent = i18n.__("Download location")
getId("clText").innerHTML = i18n.__("Current download location - ")
getId("selectLocation").textContent = i18n.__("Select Download Location")
getId("transparentText").textContent = i18n.__("Enable transparent dark mode(only Linux, needs restart)")
getId("transparentText").textContent = i18n.__("Enable transparent dark mode(only Linux, needs relaunch)")
getId("preferences").textContent = i18n.__("Preferences")
getId("selectLn").textContent = i18n.__("Select Language")
getId("selectLn").textContent = i18n.__("Select Language (Requires relaunch)")
getId("restart").textContent = i18n.__("Restart app")

@ -4,7 +4,7 @@
"About": "About",
"Download location": "Download location",
"Current download location - ": "Current download location - ",
"Enable transparent dark mode(only Linux, needs restart)": "Enable transparent dark mode(only Linux, needs restart)",
"Enable transparent dark mode(only Linux, needs relaunch)": "Enable transparent dark mode(only Linux, needs relaunch)",
"Please wait, yt-dlp is being downloaded": "Please wait, yt-dlp is being downloaded",
"Video": "Video",
"Audio": "Audio",
@ -14,7 +14,7 @@
"Select Download Location": "Select Download Location",
"More options": "More options",
"Start": "Start",
"Select Language": "Select Language",
"Select Language (Requires relaunch)": "Select Language (Requires relaunch)",
"Download particular time-range": "Download particular time-range",
"End": "End",
"If kept empty, it will start from the beginning": "If kept empty, it will start from the beginning",
@ -25,8 +25,8 @@
"Source Code is available ": "Source Code is available ",
"here": "here",
"Processing": "Processing",
"Some error has occured. Check your connection and use correct URL":"Some error has occured. Check your connection and use correct URL",
"Failed to download yt-dlp. Please check your connection and try again": "Failed to download yt-dlp. Please check your connection and try again",
"Some error has occured. Check your network and use correct URL":"Some error has occured. Check your network and use correct URL",
"Failed to download yt-dlp. Please check your network and try again": "Failed to download yt-dlp. Please check your network and try again",
"Try again":"Try again",
"Unknown size":"Unknown size",
"MB":"MB",
@ -38,5 +38,6 @@
"Preparing":"Preparing",
"Progress":"Progress",
"Speed":"Speed",
"Quality":"Quality"
"Quality":"Quality",
"Restart app":"Restart app"
}

Loading…
Cancel
Save