yt tuning

This commit is contained in:
Ondrej Zara 2019-04-14 21:02:21 +02:00
parent 0e339fc88d
commit e0ab191d72
6 changed files with 85 additions and 74 deletions

View file

@ -38,6 +38,7 @@ button {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
display: inline-flex; display: inline-flex;
white-space: nowrap;
background-color: transparent; background-color: transparent;
padding: 0; padding: 0;
border: none; border: none;
@ -576,8 +577,6 @@ nav ul li.active {
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
justify-content: center;
} }
#yt header { #yt header {
display: flex; display: flex;
@ -632,36 +631,32 @@ nav ul li.active {
#yt li:nth-child(odd) { #yt li:nth-child(odd) {
background-color: var(--bg-alt); background-color: var(--bg-alt);
} }
#yt .go { #yt header {
width: 96px; border-bottom: 1px solid var(--fg);
height: 96px;
justify-content: center;
} }
#yt .go:disabled { #yt header button + button {
position: relative; margin-left: 16px;
} }
#yt .go:disabled::before { #yt .clear {
content: ""; margin-left: auto;
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
border-top: 3px solid var(--primary);
border-radius: 50%;
animation: rotate linear 3s infinite;
} }
#yt p { #yt pre {
margin: 16px 8px; flex-grow: 1;
overflow: auto;
white-space: pre-wrap; white-space: pre-wrap;
} }
@keyframes rotate { #yt.pending header {
background-image: linear-gradient(var(--primary), var(--primary));
background-repeat: no-repeat;
background-size: 25% 4px;
animation: bar ease-in-out 3s alternate infinite;
}
@keyframes bar {
0% { 0% {
transform: rotate(0deg); background-position: 0 100%;
} }
100% { 100% {
transform: rotate(360deg); background-position: 100% 100%;
} }
} }
#settings { #settings {

View file

@ -35,6 +35,7 @@ button {
.flex-row; .flex-row;
display: inline-flex; display: inline-flex;
white-space: nowrap;
background-color: transparent; background-color: transparent;
padding: 0; padding: 0;

View file

@ -1,39 +1,33 @@
#yt { #yt {
.component; .component;
align-items: center; header {
justify-content: center; border-bottom: 1px solid var(--fg);
.go { button + button {
width: 96px; margin-left: 16px;
height: 96px;
justify-content: center;
&:disabled {
position: relative;
&::before {
content: "";
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
border-top: 3px solid var(--primary);
border-radius: 50%;
animation: rotate linear 3s infinite;
} }
} }
.clear {
margin-left: auto;
} }
p { pre {
margin: 16px 8px; flex-grow: 1;
overflow: auto;
white-space: pre-wrap; white-space: pre-wrap;
} }
&.pending header {
background-image: linear-gradient(var(--primary), var(--primary));
background-repeat: no-repeat;
background-size: 25% 4px;
animation: bar ease-in-out 3s alternate infinite;
}
} }
@keyframes rotate { @keyframes bar {
0% { transform: rotate(0deg); } 0% { background-position: 0 100%; }
100% { transform: rotate(360deg); } 100% { background-position: 100% 100%; }
} }

View file

@ -57,8 +57,12 @@
<ul></ul> <ul></ul>
</section> </section>
<section id="yt"> <section id="yt">
<button class="go" data-icon="download">Go!</button> <header>
<p></p> <button class="download" data-icon="download">Download</button>
<button class="search-download" data-icon="magnify">Search &amp; Download</button>
<button class="clear" data-icon="close">Clear</button>
</header>
<pre></pre>
</section> </section>
<section id="settings"> <section id="settings">
<dl> <dl>

View file

@ -8,41 +8,58 @@ let node;
const decoder = new TextDecoder("utf-8"); const decoder = new TextDecoder("utf-8");
function decodeChunk(byteArray) { function decodeChunk(byteArray) {
return decoder.decode(byteArray); // \r => \n
return decoder.decode(byteArray).replace(/\u000d/g, "\n");
} }
async function onClick(e) { async function post(q) {
let url = prompt("Please enter a YouTube URL:"); let pre = node.querySelector("pre");
if (!url) { return; } html.clear(pre);
let button = e.target; node.classList.add("pending");
button.disabled = true;
let p = node.querySelector("p");
p.textContent = "";
let body = new URLSearchParams(); let body = new URLSearchParams();
body.set("url", url); body.set("q", q);
let response = await fetch("/youtube", {method:"POST", body}); let response = await fetch("/youtube", {method:"POST", body});
let reader = response.body.getReader(); let reader = response.body.getReader();
while (true) { while (true) {
let { done, value } = await reader.read(); let { done, value } = await reader.read();
if (done) { break; } if (done) { break; }
p.textContent += decodeChunk(value); pre.textContent += decodeChunk(value);
pre.scrollTop = pre.scrollHeight;
} }
reader.releaseLock(); reader.releaseLock();
button.disabled = false; node.classList.remove("pending");
if (response.status == 200) { if (response.status == 200) {
mpd.command(`update ${mpd.escape(conf.ytPath)}`); mpd.command(`update ${mpd.escape(conf.ytPath)}`);
} }
} }
function download() {
let url = prompt("Please enter a YouTube URL:");
if (!url) { return; }
post(url);
}
function search() {
let q = prompt("Please enter a search string:");
if (!q) { return; }
post(`ytsearch:${q}`);
}
function clear() {
html.clear(node.querySelector("pre"));
}
export async function activate() {} export async function activate() {}
export function init(n) { export function init(n) {
node = n; node = n;
node.querySelector(".download").addEventListener("click", e => download());
let button = node.querySelector(".go").addEventListener("click", onClick); node.querySelector(".search-download").addEventListener("click", e => search());
node.querySelector(".clear").addEventListener("click", e => clear());
} }

View file

@ -5,16 +5,16 @@ const port = Number(process.argv[2]) || 8080;
const cmd = "youtube-dl"; const cmd = "youtube-dl";
//const cmd = "./test.sh"; //const cmd = "./test.sh";
function downloadYoutube(url, response) { function downloadYoutube(q, response) {
response.setHeader("Content-Type", "text/plain"); // necessary for firefox to read by chunks response.setHeader("Content-Type", "text/plain"); // necessary for firefox to read by chunks
// response.setHeader("Content-Type", "text/plain; charset=utf-8"); // response.setHeader("Content-Type", "text/plain; charset=utf-8");
// FIXME create directory // FIXME create directory
console.log("YouTube downloading", url); console.log("YouTube downloading", q);
let args = [ let args = [
"-f", "bestaudio", "-f", "bestaudio",
"-o", `${__dirname}/_youtube/%(title)s-%(id)s.%(ext)s`, "-o", `${__dirname}/_youtube/%(title)s-%(id)s.%(ext)s`,
url q
] ]
let child = require("child_process").spawn(cmd, args); let child = require("child_process").spawn(cmd, args);
@ -39,9 +39,9 @@ function handleYoutube(request, response) {
request.setEncoding("utf8"); request.setEncoding("utf8");
request.on("data", chunk => str += chunk); request.on("data", chunk => str += chunk);
request.on("end", () => { request.on("end", () => {
let url = require("querystring").parse(str)["url"]; let q = require("querystring").parse(str)["q"];
if (url) { if (q) {
downloadYoutube(url, response); downloadYoutube(q, response);
} else { } else {
response.writeHead(404); response.writeHead(404);
response.end(); response.end();