Add pwa support
@@ -0,0 +1,4 @@
|
||||
<div>
|
||||
<h1>Cannot connect to the TYTD2025 server.</h1>
|
||||
Refresh page to add to offline queue
|
||||
</div>
|
||||
106
Tesses.YouTubeDownloader.Server/res/offline.html
Normal file
@@ -0,0 +1,106 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>TYTD2025 is Offline</title>
|
||||
<link rel="stylesheet" href="/beer.min.css">
|
||||
<link rel="stylesheet" href="/theme.css">
|
||||
<script src="/offline.js" defer></script>
|
||||
<script type="module" src="/beer.min.js" defer></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="row">
|
||||
<div class="max"></div>
|
||||
<div class="min">
|
||||
<img src="tytd-128.png" alt="tytd-logo">
|
||||
</div>
|
||||
<div class="max"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="max"></div>
|
||||
<div class="min">
|
||||
<h3>Cannot connect to the TYTD2025 server.</h3>
|
||||
</div>
|
||||
<div class="max"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="max"></div>
|
||||
<div class="min">
|
||||
<form>
|
||||
|
||||
<div class="field label border small fill">
|
||||
<input id="url" type="text">
|
||||
<label>Url or id</label>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="max">
|
||||
<div class="field label suffix border fill">
|
||||
<select id="res">
|
||||
|
||||
|
||||
<option value="NoDownload">Don't Download</option>
|
||||
|
||||
|
||||
|
||||
<option value="LowVideo" selected="">Low (muxed by YouTube)</option>
|
||||
|
||||
|
||||
|
||||
<option value="VideoOnly">Highest video (no audio)</option>
|
||||
|
||||
|
||||
|
||||
<option value="AudioOnly">Highest audio (no video)</option>
|
||||
|
||||
|
||||
|
||||
<option value="MP3">Convert to MP3</option>
|
||||
|
||||
|
||||
|
||||
<option value="FLAC">Convert to FLAC</option>
|
||||
|
||||
|
||||
|
||||
<option value="MP4">Convert to MP4</option>
|
||||
|
||||
|
||||
|
||||
<option value="MKV">Mux to MKV (no transcoding)</option>
|
||||
|
||||
|
||||
|
||||
<option value="DontConvert">Don't convert or Mux</option>
|
||||
|
||||
|
||||
</select>
|
||||
<label>Resolution</label>
|
||||
<i>arrow_drop_down</i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="min">
|
||||
<button id="btn">
|
||||
<i>add</i>
|
||||
Add when online
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="max"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
btn.onclick = (evt)=>{
|
||||
evt.preventDefault();
|
||||
addOffline(url.value, res.value);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
54
Tesses.YouTubeDownloader.Server/res/offline.js
Normal file
@@ -0,0 +1,54 @@
|
||||
function addOffline(url,res)
|
||||
{
|
||||
var videos = JSON.parse(localStorage.getItem("videos") ?? "[]");
|
||||
videos.push({
|
||||
url: url,
|
||||
res: res
|
||||
});
|
||||
localStorage.setItem('videos',JSON.stringify(videos));
|
||||
}
|
||||
|
||||
async function syncOffline()
|
||||
{
|
||||
const json = localStorage.getItem("videos") ?? "[]";
|
||||
if(json !== "[]")
|
||||
{
|
||||
const resp = await fetch('/api/v1/add',{
|
||||
body: json,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: "POST"
|
||||
});
|
||||
if(resp.ok)
|
||||
{
|
||||
localStorage.removeItem('videos');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(navigator.online)
|
||||
{
|
||||
syncOffline();
|
||||
}
|
||||
|
||||
window.addEventListener('online',()=>{
|
||||
syncOffline();
|
||||
});
|
||||
|
||||
async function getPersonalTempLink()
|
||||
{
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const ent = searchParams.get("name");
|
||||
if(ent)
|
||||
{
|
||||
const resp=await fetch(`./api/v1/personal_tmp_link?name=${encodeURIComponent(ent)}`);
|
||||
if(resp.ok)
|
||||
{
|
||||
const text = await resp.text();
|
||||
the_playlist_url.innerText = text;
|
||||
the_playlist_url.href = text;
|
||||
ui("#dialog");
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Tesses.YouTubeDownloader.Server/res/service_worker.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const assets = ["<@ASSETS@>"];
|
||||
|
||||
const staticCacheName = "tytd-static-<@BUILD_TIME@>";
|
||||
|
||||
self.addEventListener('install',evt => {
|
||||
evt.waitUntil(
|
||||
caches.open(staticCacheName).then(cache =>{
|
||||
cache.addAll(assets);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate',(evt)=>{
|
||||
evt.waitUntil(
|
||||
caches.keys().then(keys => {
|
||||
return Promise.all(keys.filter(key => key !== staticCacheName).map(key => caches.delete(key)));
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', evt => {
|
||||
const uri = new URL(evt.request.url);
|
||||
|
||||
evt.respondWith(
|
||||
|
||||
caches.match(evt.request).then(cacheRes=>{
|
||||
return cacheRes || fetch(evt.request);
|
||||
}).catch(()=>{
|
||||
if(uri.pathname === '/queue-size')
|
||||
{
|
||||
return new Response('<span hx-trigger="every 5000ms" hx-target="this" hx-push-url="false" hx-indicator="none" hx-get="./queue-size" hx-swap="outerHTML" class="badge">?</span>',{
|
||||
headers: { 'Content-Type': 'text/html' }
|
||||
});
|
||||
}
|
||||
if(uri.pathname === "/progress")
|
||||
{
|
||||
return caches.match("/offline-progress.html");
|
||||
}
|
||||
return caches.match('/offline.html');
|
||||
})
|
||||
);
|
||||
});
|
||||
73
Tesses.YouTubeDownloader.Server/res/site.webmanifest
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"short_name": "TYTD2025",
|
||||
"name": "Tesses YouTubeDownloader 2025",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"theme_color": "#ffb2be",
|
||||
"background_color": "#241e1f",
|
||||
"description": "A web based YouTube archiver to preserve videos that might be removed",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/tytd.svg",
|
||||
"sizes": "192x192 256x256 384x384 512x512",
|
||||
"type": "image/svg+xml",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/tytd-128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/tytd-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/tytd-256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/tytd-384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/tytd-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/tytd-1024.png",
|
||||
"sizes": "1024x1024",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"shortcuts": [
|
||||
{
|
||||
"name": "Open Downloads",
|
||||
"short_name": "Downloads",
|
||||
"description": "Open Downloads page",
|
||||
"url": "/downloads"
|
||||
},
|
||||
{
|
||||
"name": "Open Installed Plugins",
|
||||
"short_name": "Installed plugins",
|
||||
"description": "Open the installed plugins page",
|
||||
"url": "/plugins"
|
||||
},
|
||||
{
|
||||
"name": "Open Download Plugins",
|
||||
"short_name": "Download plugins",
|
||||
"description": "Open the download plugins page",
|
||||
"url": "/plugins-download"
|
||||
},
|
||||
{
|
||||
"name": "Open Settings",
|
||||
"short_name": "Settings",
|
||||
"description": "Open settings page",
|
||||
"url": "/settings"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Tesses.YouTubeDownloader.Server/res/tytd-1024.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
Tesses.YouTubeDownloader.Server/res/tytd-192.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Tesses.YouTubeDownloader.Server/res/tytd-256.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
Tesses.YouTubeDownloader.Server/res/tytd-384.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
Tesses.YouTubeDownloader.Server/res/tytd-512.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |