backend/src/templates/watch.eta

268 lines
7.0 KiB
Plaintext

<% layout('./layout') %>
<% if (it.isMissing) { %>
<div class="error">
<h2>Archive not found</h2>
<button onclick="window.location.href='/save?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D<%= it.id %>'">
Archive Me!
</button>
</div>
<% } else { %>
<div class="content-wrapper">
<div class="main-content">
<div class="report">
<a href="abuse">[report abuse]</a>
<div class="space"></div>
<a href="dmca">[dmca]</a>
</div>
<% if (it.transparency.length != 0) { %>
<div class="reports">
<span class="reports-title">Somebody has complained about this video...</span> <br/>
<% it.transparency.forEach(function(t){ %>
<a href="<%= t.details %>"><%= t.title %></a>
<% }) %>
</div>
<% } %>
<div class="video-wrapper">
<div class="video-loading hidden" id="video-loading">Loading...</div>
<video id="video-player" src="<%= it.source %>" poster="<%= it.thumbnail %>" controls preload="metadata"></video>
</div>
<h1><%= it.v_title %></h1>
<div class="channel-profile">
<img src="<%= it.channelAvatar %>" />
<span class="channel-name">
<a href="/channel/<%= it.channelId %>">
<%= it.channel %>
<% if (it.channelVerified) { %>
<div class="verified"></div>
<% } %>
</a>
</span>
</div>
<div class="metadata">
<p class="date">
Published on <%= it.published %> | Archived on <%= it.archived %>
<a href="<%= it.source %>" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg>
</a>
</p>
<p class="description"><%~ it.description %></p>
</div>
</div>
</div>
<% } %>
<style>
.content-wrapper {
position: relative;
min-height: 100vh;
}
.main-content {
width: 65%;
margin: 0 auto;
}
.icon {
width: 1.25rem;
height: 1.25rem;
margin-left: 0.5em;
}
.report {
text-align: right;
margin-top: 5px;
}
.space {
display: inline-block;
width: 0.5%;
}
video {
width: 100%;
max-height: 720px;
display: block;
margin-top: 5px;
}
h1 {
position: relative;
margin: 1rem 0;
}
.error {
text-align: center;
}
.error h2 {
font-size: 30px;
display: flex;
place-items: center;
justify-content: center;
}
.channel-profile {
display: flex;
align-items: center;
}
.channel-profile img {
border-radius: 50%;
display: inline-block;
width: 3em;
height: 3em;
}
.channel-name {
padding-left: 10px;
font-size: 1.2em;
}
.date {
font-size: 17px;
font-weight: bold;
display: flex;
}
.description {
margin-top: 1rem;
}
.verified {
height: 15px;
content: url('https://api.iconify.design/ion/checkmark-circle.svg');
display: inline-block;
}
.reports {
background-color: #fff2cf;
border: 2px dashed #dab75e;
padding: 10px;
margin-top: 5px;
margin-bottom: 1rem;
}
.reports-title {
font-size: large;
font-weight: 600;
}
.video-wrapper {
position: relative;
display: inline-block;
width: 100%;
max-height: 720px;
}
.video-wrapper video {
width: 100%;
max-height: 720px;
display: block;
}
.video-loading {
position: absolute;
top: 0;
left: 0;
color: white;
font-size: 1em;
padding: 6px 10px;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
border-radius: 0;
z-index: 2;
transition: opacity 0.3s ease;
font-size: large;
max-width: 500px;
}
.video-loading.hidden {
opacity: 0;
pointer-events: none;
}
@media (max-width: 1100px) {
h1 {
font-size: 1.65em;
}
.date {
font-size: 1em;
}
.channel-name {
font-size: 1em
}
.icon {
display: none;
}
.channel-profile img {
width: 2.5em;
height: 2.5em;
}
.main-content {
width: 90%
}
}
</style>
<script is:inline>
function initVideoLoading() {
const video = document.getElementById('video-player');
const loading = document.getElementById('video-loading');
if (!video || !loading) return;
loading?.classList.remove("hidden");
const hide = () => {
if (!loading.classList.contains('hidden')) {
loading.classList.add('hidden');
loading.addEventListener('transitionend', () => loading.remove(), { once: true });
}
};
// bunch of events that show readyness
['loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'play'].forEach(evt =>
video.addEventListener(evt, hide)
);
// weird firefox something
video.addEventListener('click', hide);
video.addEventListener('keydown', hide);
video.addEventListener('pointerdown', hide);
video.addEventListener('error', () => {
loading.innerHTML = 'Video failed to load.';
loading.innerHTML += '<p style="font-size: medium;">This is not supposed to happen. Please email me at admin@preservetube.com with as much debugging information.</p>' +
'<p style="font-size: medium;">Please include your browser console logs. <a style="font-style: italic;" href="https://support.happyfox.com/kb/article/882-accessing-the-browser-console-and-network-logs/">' +
'See here on how to access them.</a> Please note you might have to refresh the page for anything to show up.</p>'
});
// video already has data (i.e. cached)
if (video.readyState > 0) hide();
// add an extra message after 10s
const FALLBACK_MS = 10000;
const fallbackTimer = setTimeout(() => {
if (!loading.classList.contains('hidden')) {
loading.innerHTML = 'Taking longer than usual to load...';
loading.innerHTML += '<p style="font-size: medium;">This might be due one of multiple reasons:</p>'
+ '<ol style="font-size: medium;"><li>This video is large. Depending on your browser, it might try loading the full thing at one time, which will slow things down.</li>'
+ '<li>Preservetube servers are overloaded. This happens once in a while, please be patient.</li><li>You\'re in an unfavourable region, which has a bad connection to our servers.</li></ol>'
+ '<p style="font-size: medium;">If this takes an unusual amount of time, even after considering the above mentioned reasons, please email me at admin@preservetube.com. Don\'t forget to include your aproximate region, your browser and OS.</p>';
}
}, FALLBACK_MS);
// clear fallback once overlay removed
loading.addEventListener('transitionend', () => clearTimeout(fallbackTimer), { once: true });
}
initVideoLoading();
</script>