268 lines
7.0 KiB
Plaintext
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> |