460 lines
37 KiB
HTML
460 lines
37 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta charset="UTF-8"/>
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||
|
<meta property="og:title" content="🎵️ TiktOctt"/>
|
||
|
<meta OctoSpaccHubSdk="Url" content="https://hub.octt.eu.org/TiktOctt/"/>
|
||
|
<meta OctoSpaccHubSdk="WebManifestExtra" content="'display':'standalone', 'icons':[{ 'src':'./logo.png', 'type':'image/png', 'sizes':'1024x1024' }],"/>
|
||
|
<style>
|
||
|
:root {
|
||
|
--footerHeight: 40px;
|
||
|
--hudBaseHeight: 8em;
|
||
|
--screenPadding: 8px;
|
||
|
--hudButtonSize: 48px;
|
||
|
}
|
||
|
body {
|
||
|
margin: 0;
|
||
|
color: white;
|
||
|
background-color: black;
|
||
|
overflow: hidden;
|
||
|
height: 100%;
|
||
|
font-family: sans-serif;
|
||
|
}
|
||
|
a {
|
||
|
color: white !important;
|
||
|
}
|
||
|
.videosContainer {
|
||
|
position: fixed;
|
||
|
height: 100%;
|
||
|
max-height: 100%;
|
||
|
overflow-y: scroll;
|
||
|
scrollbar-width: none;
|
||
|
/* scroll-snap-type: mandatory;
|
||
|
scroll-snap-points-y: repeat(100vh); */
|
||
|
scroll-snap-type: y mandatory;
|
||
|
}
|
||
|
.videoItem {
|
||
|
scroll-snap-align: start;
|
||
|
scroll-snap-stop: always;
|
||
|
position: relative;
|
||
|
/* height: calc(100vh - var(--footerHeight)); */
|
||
|
}
|
||
|
.videosList, .videoItem, .videoItem > video {
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
}
|
||
|
.videoItem > div {
|
||
|
position: relative;
|
||
|
bottom: var(--footerHeight);
|
||
|
/* margin: 8px;
|
||
|
z-index: 1;
|
||
|
padding-left: 8px;
|
||
|
padding-right: 8px; */
|
||
|
}
|
||
|
.videoItem > .hud {
|
||
|
height: calc(2 * var(--hudBaseHeight) + var(--screenPadding));
|
||
|
bottom: calc(var(--footerHeight) + var(--hudBaseHeight) + var(--screenPadding) + 5em);
|
||
|
background-image: linear-gradient(to bottom, rgba(0,0,0,0.0), rgba(0,0,0,1.0));
|
||
|
}
|
||
|
.videoItem > .hud > * {
|
||
|
position: relative;
|
||
|
}
|
||
|
.videoItem > .hud > p {
|
||
|
/* margin: 8px; */
|
||
|
/* approximation based on all the <p>s */
|
||
|
bottom: calc((-1 * var(--hudBaseHeight)) + (2 * var(--screenPadding)) + 4em - (2 * var(--footerHeight)));
|
||
|
padding-left: var(--screenPadding);
|
||
|
padding-right: var(--screenPadding);
|
||
|
max-width: calc(100vw - (2 * var(--screenPadding)));
|
||
|
overflow: hidden;
|
||
|
white-space: nowrap;
|
||
|
text-overflow: ellipsis;
|
||
|
}
|
||
|
.videoItem > .hud > p.title {
|
||
|
font-size: larger;
|
||
|
margin-top: var(--screenPadding);
|
||
|
padding-bottom: var(--screenPadding);
|
||
|
}
|
||
|
.videoItem > .hud > p.subtitle > a {
|
||
|
text-decoration: none;
|
||
|
}
|
||
|
.videoItem > .hud > p.status {
|
||
|
font-size: small;
|
||
|
top: 11em;
|
||
|
/* margin-bottom: calc(-1 * var(--screenPadding)); */
|
||
|
/* padding-top: var(--screenPadding); */
|
||
|
}
|
||
|
.videoItem > .hud > button {
|
||
|
position: relative;
|
||
|
display: block;
|
||
|
left: calc(100vw - var(--hudButtonSize) - (2 * var(--screenPadding)));
|
||
|
/* bottom: calc(var(--hudButtonSize) /* + 4em */ /* (2 * var(--screenPadding)) ); */
|
||
|
bottom: calc(4em + (2 * var(--screenPadding)));
|
||
|
margin-bottom: calc(2 * var(--screenPadding));
|
||
|
background: none;
|
||
|
border: none;
|
||
|
}
|
||
|
.videoItem > .hud > button, .videoItem > .hud > button > * {
|
||
|
width: var(--hudButtonSize);
|
||
|
height: var(--hudButtonSize);
|
||
|
}
|
||
|
/* .videoItem > .hud > .icon.pause {
|
||
|
display: none;
|
||
|
}
|
||
|
.videoItem.paused > .hud > .icon.pause {
|
||
|
display: revert;
|
||
|
position: fixed;
|
||
|
max-width: 20%;
|
||
|
max-height: 20%;
|
||
|
} */
|
||
|
/* .scrollLoader {
|
||
|
height: var(--footerHeight);
|
||
|
display: flex;
|
||
|
background: #eee;
|
||
|
justify-content: center;
|
||
|
} */
|
||
|
.framesArea {
|
||
|
width: 100vw;
|
||
|
height: 100%;
|
||
|
position: absolute;
|
||
|
z-index: 3;
|
||
|
}
|
||
|
.framesArea > * {
|
||
|
margin: 2em;
|
||
|
width: calc(100vw - 4em);
|
||
|
height: calc(100% - 4em);
|
||
|
}
|
||
|
.toastArea {
|
||
|
position: fixed;
|
||
|
z-index: 1;
|
||
|
width: 100vw;
|
||
|
text-align: center;
|
||
|
padding-top: 1em;
|
||
|
top: 1em;
|
||
|
}
|
||
|
.toastArea > span {
|
||
|
padding: 0.5em;
|
||
|
position: fixed;
|
||
|
left: 0;
|
||
|
right: 0;
|
||
|
margin: auto;
|
||
|
width: fit-content;
|
||
|
}
|
||
|
.framesArea > *, .toastArea > span {
|
||
|
background-color: #222;
|
||
|
border-radius: 2px;
|
||
|
}
|
||
|
.contentFrame > .header {
|
||
|
background: black;
|
||
|
padding: 0.5em;
|
||
|
}
|
||
|
.contentFrame > .header > button {
|
||
|
float: right;
|
||
|
}
|
||
|
.contentFrame > .header > span {
|
||
|
text-overflow: ellipsis;
|
||
|
overflow: hidden;
|
||
|
display: block ruby;
|
||
|
padding-right: var(--screenPadding);
|
||
|
}
|
||
|
.contentFrame > .content {
|
||
|
padding: 1em;
|
||
|
overflow: auto;
|
||
|
height: calc(100% - 4em);
|
||
|
}
|
||
|
.contentFrame > .content * {
|
||
|
max-width: 100% !important;
|
||
|
}
|
||
|
.audioNag {
|
||
|
position: fixed;
|
||
|
z-index: 2;
|
||
|
margin: var(--screenPadding);
|
||
|
font-size: large;
|
||
|
}
|
||
|
.splash {
|
||
|
width: 100%;
|
||
|
height: 100vh;
|
||
|
text-align: center;
|
||
|
background-color: black;
|
||
|
position: absolute;
|
||
|
z-index: 3;
|
||
|
}
|
||
|
.splash > img {
|
||
|
position: absolute;
|
||
|
max-width: 60%;
|
||
|
max-height: 40%;
|
||
|
}
|
||
|
.splash > img, .icon.pause {
|
||
|
margin: auto;
|
||
|
top: 0;
|
||
|
bottom: 0;
|
||
|
left: 0;
|
||
|
right: 0;
|
||
|
}
|
||
|
.footer {
|
||
|
position: fixed;
|
||
|
bottom: 0;
|
||
|
width: 100%;
|
||
|
height: var(--footerHeight);
|
||
|
background: black;
|
||
|
}
|
||
|
</style>
|
||
|
</head>
|
||
|
<body>
|
||
|
<div class="splash">
|
||
|
<img src="./logo.png"/>
|
||
|
</div>
|
||
|
<div class="toastArea"></div>
|
||
|
<button class="audioNag">🔊️ Unmute</button>
|
||
|
<div class="framesArea" style="display: none;"></div>
|
||
|
<div class="videosContainer">
|
||
|
<div class="videosList"></div>
|
||
|
<!-- <p class="scrollLoader"></p> -->
|
||
|
</div>
|
||
|
<!-- <div class="footer"></div> -->
|
||
|
<script>(function(){
|
||
|
|
||
|
const icons = {
|
||
|
/* Solar Broken Line Icons, Solar Icons */
|
||
|
pause /* <https://www.svgrepo.com/svg/529128/pause-circle> */: '<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 9.5C8 9.03406 8 8.80109 8.07612 8.61732C8.17761 8.37229 8.37229 8.17761 8.61732 8.07612C8.80109 8 9.03406 8 9.5 8C9.96594 8 10.1989 8 10.3827 8.07612C10.6277 8.17761 10.8224 8.37229 10.9239 8.61732C11 8.80109 11 9.03406 11 9.5V14.5C11 14.9659 11 15.1989 10.9239 15.3827C10.8224 15.6277 10.6277 15.8224 10.3827 15.9239C10.1989 16 9.96594 16 9.5 16C9.03406 16 8.80109 16 8.61732 15.9239C8.37229 15.8224 8.17761 15.6277 8.07612 15.3827C8 15.1989 8 14.9659 8 14.5V9.5Z" stroke="#FFFFFF" stroke-width="1.5"/><path d="M13 9.5C13 9.03406 13 8.80109 13.0761 8.61732C13.1776 8.37229 13.3723 8.17761 13.6173 8.07612C13.8011 8 14.0341 8 14.5 8C14.9659 8 15.1989 8 15.3827 8.07612C15.6277 8.17761 15.8224 8.37229 15.9239 8.61732C16 8.80109 16 9.03406 16 9.5V14.5C16 14.9659 16 15.1989 15.9239 15.3827C15.8224 15.6277 15.6277 15.8224 15.3827 15.9239C15.1989 16 14.9659 16 14.5 16C14.0341 16 13.8011 16 13.6173 15.9239C13.3723 15.8224 13.1776 15.6277 13.0761 15.3827C13 15.1989 13 14.9659 13 14.5V9.5Z" stroke="#FFFFFF" stroke-width="1.5"/><path d="M7 3.33782C8.47087 2.48697 10.1786 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 10.1786 2.48697 8.47087 3.33782 7" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
||
|
share /* <https://www.svgrepo.com/svg/529194/share> */: `<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4 12C4 13.3807 5.11929 14.5 6.5 14.5C7.88071 14.5 9 13.3807 9 12C9 10.6193 7.88071 9.5 6.5 9.5" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round"/><path d="M14 6.5L9 10" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round"/><path d="M14 17.5L9 14" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round"/><path d="M16.5 21C17.8807 21 19 19.8807 19 18.5C19 17.1193 17.8807 16 16.5 16C15.1193 16 14 17.1193 14 18.5" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round"/><path d="M18.665 6.74993C17.9746 7.94566 16.4457 8.35535 15.2499 7.66499C14.0542 6.97464 13.6445 5.44566 14.3349 4.24993C15.0252 3.0542 16.5542 2.64451 17.7499 3.33487" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round"/></svg>`,
|
||
|
heart /* */: `<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 5.50063L11.4596 6.02073C11.463 6.02421 11.4664 6.02765 11.4698 6.03106L12 5.50063ZM8.96173 18.9109L8.49742 19.4999L8.96173 18.9109ZM15.0383 18.9109L14.574 18.3219L15.0383 18.9109ZM7.00061 16.4209C6.68078 16.1577 6.20813 16.2036 5.94491 16.5234C5.68169 16.8432 5.72758 17.3159 6.04741 17.5791L7.00061 16.4209ZM2.34199 13.4115C2.54074 13.7749 2.99647 13.9084 3.35988 13.7096C3.7233 13.5108 3.85677 13.0551 3.65801 12.6917L2.34199 13.4115ZM13.4698 8.03034C13.7627 8.32318 14.2376 8.32309 14.5304 8.03014C14.8233 7.7372 14.8232 7.26232 14.5302 6.96948L13.4698 8.03034ZM2.75 9.1371C2.75 6.98623 3.96537 5.18252 5.62436 4.42419C7.23607 3.68748 9.40166 3.88258 11.4596 6.02073L12.5404 4.98053C10.0985 2.44352 7.26409 2.02539 5.00076 3.05996C2.78471 4.07292 1.25 6.42503 1.25 9.1371H2.75ZM8.49742 19.4999C9.00965 19.9037 9.55955 20.3343 10.1168 20.6599C10.6739 20.9854 11.3096 21.25 12 21.25V19.75C11.6904 19.75 11.3261 19.6293 10.8736 19.3648C10.4213 19.1005 9.95208 18.7366 9.42605 18.3219L8.49742 19.4999ZM15.5026 19.4999C16.9292 18.3752 18.7528 17.0866 20.1833 15.4758C21.6395 13.8361 22.75 11.8026 22.75 9.1371H21.25C21.25 11.3345 20.3508 13.0282 19.0617 14.4798C17.7469 15.9603 16.0896 17.1271 14.574 18.3219L15.5026 19.4999ZM22.75 9.1371C22.75 6.42503 21.2153 4.07292 18.9992 3.05996C16.7359 2.02539 13.9015 2.44352 11.4596 4.98053L12.5404 6.02073C14.5983 3.88258 16.7639 3.68748 18.3756 4.42419C20.0346 5.18252 21.25 6.98623 21.25 9.1371H22.75ZM14.574 18.3219C14.0479 18.7366 13.5787 19.1005 13.1264 19.3648C12.6739 19.6293 12.3096 19.75 12 19.75V21.25C12.6904 21.25 13.3261 20.9854 13.8832 20.6599C14.4405 20.3343 14.9903 19.9037 15.5026 19.4999L14.574 18.3219ZM9.42605 18.3219C8.63014 17.6945 7.82129 17.0963 7.00061 16.4209L6.04741 17.5791C6.87768 18.2624 7.75472 18.9144 8.49742 19.4999L9.42605 18.3219ZM3.65801 12.6917C3.0968 11.6656 2.75 10.5033 2.75 9.1371H1.25C1.25 10.7746 1.66995 12.1827 2.34199 13.4115L3.65801 12.6917ZM11.4698 6.03106L13.4698 8.03034L14.5302 6.96948L12.5302 4.97021L11.4698 6.03106Z" fill="#FFFFFF"/></svg>`,
|
||
|
heartFilled: `<svg width="800" height="800" viewBox="0 0 24 24" fill="none" version="1.1" id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"><defs id="defs1"/><path style="fill:#1a1a1a;stroke-width:0.03" d="m 3.066315,12.73195 c 0.028084,0.16036 0.0182,0.401349 0.129264,0.549433 0.1367685,0.182358 0.2882154,0.404433 0.4656573,0.551831 0.1623813,0.134887 0.3395487,0.262856 0.4739676,0.430879 0.1026399,0.1283 0.198972,0.259487 0.3016158,0.387792 0.113082,0.141353 0.2792253,0.243037 0.3877917,0.387792 0.1058463,0.01536 0.017894,0.09147 0.043088,0.129264 0.086176,0.129264 0.064632,0.04309 0.129264,0.129264 0.050249,0.067 0.079015,0.148441 0.1292637,0.21544 0.1206465,0.160862 0.3102336,0.270018 0.4308798,0.43088 0.038539,0.05138 0.050547,0.118907 0.086176,0.172351 0.1833339,0.275001 0.5073621,0.476344 0.7245111,0.724515 0.1367106,0.156241 0.240207,0.401749 0.4267035,0.512876 0.3683847,0.219506 -0.077144,-0.108835 0.4309008,0.259937 0.135204,0.09814 0.2675682,0.200385 0.395913,0.307339 0.046812,0.03901 0.07523,0.101095 0.1292637,0.129264 0.1558587,0.08125 0.3492555,0.173342 0.5007084,0.254199 0.094294,0.05034 0.2782896,0.248841 0.3396438,0.296561 0.1133721,0.08818 0.2343669,0.16658 0.3447039,0.258528 0.062416,0.05201 0.1073538,0.123603 0.1723518,0.172352 0.025693,0.01927 0.063395,0.02045 0.086176,0.04309 0.042571,0.0423 0.013019,0.09028 0.1160094,0.158551 0.1583157,0.104939 0.3542865,0.179986 0.5170557,0.258528 0.034114,0.01646 0.04779,0.061 0.080348,0.08035 0.099533,0.05917 0.194102,0.129347 0.301616,0.172352 0.02667,0.01067 0.0601,-0.01206 0.08618,0 0.01206,0.0056 -0.0094,0.03046 0,0.03986 0.03557,0.03557 0.74521,0.359462 0.85853,0.387791 0.12282,0.03071 0.260911,0.01121 0.383184,0.04309 0.173419,0.04521 0.346389,0.08748 0.513521,0.129264 0.0784,0.0196 0.746728,0.0091 0.758994,0 0.03247,-0.02399 0.05101,-0.06489 0.08564,-0.08564 0.337832,-0.202359 0.0222,0.0058 0.172352,-0.04309 0.19465,-0.06343 0.424696,-0.140439 0.597656,-0.255746 0.40672,-0.271147 0.842162,-0.507739 1.279142,-0.726244 0.279123,-0.139571 0.672905,-0.629816 0.899325,-0.856237 0.112345,-0.112345 0.220742,-0.245534 0.344704,-0.344704 0.08087,-0.0647 0.177652,-0.107651 0.258528,-0.172351 0.06344,-0.05076 0.105083,-0.126788 0.172351,-0.172352 0.01133,-0.0077 0.03137,0.0097 0.04105,0 0.07641,-0.07642 0.120947,-0.185623 0.21544,-0.256493 0.04162,-0.03122 0.27234,-0.175455 0.293894,-0.208262 0.07414,-0.112851 0.148749,-0.211939 0.258528,-0.299762 0.190576,-0.152461 0.409093,-0.275569 0.603231,-0.43088 0.03172,-0.02538 0.04984,-0.06801 0.08618,-0.08618 0.02569,-0.01285 0.06048,0.01285 0.08618,0 0.01285,-0.0064 -0.008,-0.03114 0,-0.04309 0.02253,-0.0338 0.05368,-0.0618 0.08618,-0.08618 0.07698,-0.05773 0.19126,-0.105363 0.258528,-0.172352 0.02264,-0.02255 0.02049,-0.06304 0.04309,-0.08564 0.05139,-0.05139 0.159407,-0.101516 0.214903,-0.129264 0.08322,-0.04161 0.140935,-0.159561 0.21544,-0.21544 0.318335,-0.238751 0.661753,-0.494545 0.904847,-0.818671 0.210029,-0.280038 0.297878,-0.594508 0.43088,-0.904847 0.03795,-0.08856 0.0988,-0.167125 0.129264,-0.258528 0.01408,-0.04225 0.05505,-0.249747 0.08618,-0.301616 0.0209,-0.03483 0.06527,-0.05134 0.08618,-0.08618 0.05429,-0.09048 0.319738,-0.636681 0.342674,-0.728424 0.007,-0.02787 -0.0091,-0.05893 0,-0.08618 0.02212,-0.06637 0.106845,-0.142684 0.129264,-0.20994 0.0091,-0.02725 -0.007,-0.05831 0,-0.08618 0.02007,-0.08029 0.106379,-0.146786 0.129263,-0.21544 0.0208,-0.06239 0.01343,-0.153282 0.04309,-0.211664 0.04864,-0.09575 0.144642,-0.192383 0.171816,-0.301078 0.03314,-0.132559 -0.005,-0.269773 0.03874,-0.401057 0.02031,-0.06094 0.06362,-0.11221 0.08618,-0.172352 0.0619,-0.165077 0.07349,-0.349735 0.129264,-0.517056 0.162666,-0.4879978 0.290899,-1.0797424 0.21544,-1.6079563 -0.01946,-0.1362099 -0.05541,-0.2647371 -0.08618,-0.3877917 -0.01558,-0.062314 -0.0706,-0.1100379 -0.08618,-0.1723521 -0.02015,-0.080614 -0.01703,-0.18036 -0.04309,-0.2585277 -0.0064,-0.01927 -0.034,-0.02492 -0.04309,-0.043088 -0.04957,-0.099146 -0.176085,-0.4359618 -0.214893,-0.5590665 -0.07577,-0.2403648 -0.11693
|
||
|
};
|
||
|
|
||
|
let currentVideoElem, firstVideoElem, lastVideoElem;
|
||
|
let userInteracted = false;
|
||
|
let preloadCount = 6;
|
||
|
const postsCache = {};
|
||
|
const postsHistory = [];
|
||
|
|
||
|
const scrollObserver = new IntersectionObserver(function(elems){
|
||
|
for (elem of elems) {
|
||
|
if (elem.isIntersecting) {
|
||
|
addVideos();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
function jsonStorageApi (key, setValue) {
|
||
|
return JSON.parse(localStorage[setValue !== undefined ? 'setItem' : 'getItem'](
|
||
|
`org.eu.octt.TiktOctt/v1/${key}`, JSON.stringify(setValue)) || '{}');
|
||
|
}
|
||
|
|
||
|
async function pullNewVideos () {
|
||
|
const siteUrl = 'https://octospacc.altervista.org';
|
||
|
const postsRequest = await fetch(`${siteUrl}/wp-content/uploads/${siteUrl.split('.').slice(0, 1)[0].split('//')[1]}/scripts/stuff.php?&Thing=SiteWpJsonCors&AccessToken=9ab6e20c&$Query=${encodeURIComponent(`wp/v2/posts?orderby=rand&search=wp-block-video&per_page=${preloadCount * 4}`)}`);
|
||
|
const postsData = await postsRequest.json();
|
||
|
for (const post of postsData) {
|
||
|
if (!postsCache[post.id]) {
|
||
|
post.videoUrl = post.content.rendered.split('</video>')[0].split('>').slice(-2)[0].split('src="')[1].split('"')[0]
|
||
|
.replaceAll(`${siteUrl}/wp-content/uploads/`, 'https://octospacc.github.io/microblog-mirror/assets/uploads/');
|
||
|
post.contentHtml = post.content.rendered
|
||
|
.replaceAll('<video ', '<!-- <video ').replaceAll('</video>', '</video-none> -->');
|
||
|
try {
|
||
|
const videoRequest = await fetch(post.videoUrl, { method: 'HEAD' });
|
||
|
if (videoRequest.status === 200) {
|
||
|
postsCache[post.id] = post;
|
||
|
}
|
||
|
} catch(err) {}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function onUserInteract () {
|
||
|
userInteracted = true;
|
||
|
if (currentVideoElem) {
|
||
|
currentVideoElem.muted = false;
|
||
|
}
|
||
|
document.querySelector('.audioNag')?.remove();
|
||
|
}
|
||
|
|
||
|
function theAlgorithm () {
|
||
|
const posts = Object.values(postsCache);
|
||
|
let post = posts[~~(Math.random() * posts.length)];
|
||
|
// ensure a new random video is shown until we exhaust them
|
||
|
if (postsHistory.includes(post.id) && (postsHistory.length < posts.length)) {
|
||
|
while (postsHistory.includes(post.id)) {
|
||
|
post = posts[~~(Math.random() * posts.length)];
|
||
|
}
|
||
|
}
|
||
|
// TODO fix never show the exact same post two times next to each other, leads to frustration
|
||
|
//while (post.id === postsHistory.slice(-1)[0]) {
|
||
|
// post = posts[~~(Math.random() * posts.length)];
|
||
|
//}
|
||
|
postsHistory.push(post.id);
|
||
|
return post;
|
||
|
}
|
||
|
|
||
|
function cleanExcerpt (text) {
|
||
|
text = text.trim();
|
||
|
if (text.split('>')[0].split(' ')[0].split('<')[1] === 'div') {
|
||
|
text = text.split('</div>')[1];
|
||
|
}
|
||
|
return text.replaceAll('<p>', '').replaceAll('<p ', '').replaceAll('</p>', '');
|
||
|
}
|
||
|
|
||
|
function heartPostState (id, buttonElem, invert) {
|
||
|
let hearts = jsonStorageApi('hearts');
|
||
|
if (invert) {
|
||
|
hearts[id] = !hearts[id];
|
||
|
jsonStorageApi('hearts', hearts);
|
||
|
}
|
||
|
const icon = icons[hearts[id] ? 'heartFilled' : 'heart'];
|
||
|
if (buttonElem) {
|
||
|
buttonElem.innerHTML = icon;
|
||
|
}
|
||
|
return icon;
|
||
|
}
|
||
|
|
||
|
function shareLink () {
|
||
|
var link = this.parentElement.querySelector('a').href;
|
||
|
navigator.clipboard.writeText(link);
|
||
|
document.querySelector('.toastArea').appendChild(Object.assign(document.createElement('span'), { innerHTML: `Copied to clipboard` }));
|
||
|
setTimeout((function(){
|
||
|
document.querySelector('.toastArea > span').remove();
|
||
|
}), 2000);
|
||
|
if ('share' in navigator) {
|
||
|
navigator.share(link);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async function addVideos () {
|
||
|
const fragmentElem = document.createDocumentFragment();
|
||
|
if (firstVideoElem) { //if (lastVideoElem) {
|
||
|
scrollObserver.unobserve(firstVideoElem);//lastVideoElem);
|
||
|
firstVideoElem = null;
|
||
|
}
|
||
|
try {
|
||
|
await pullNewVideos();
|
||
|
} catch(err) {
|
||
|
setTimeout(addVideos, 1000);
|
||
|
return;
|
||
|
}
|
||
|
for (let i=0; i<preloadCount; i++) {
|
||
|
const post = theAlgorithm();
|
||
|
const itemElem = document.createElement('div');
|
||
|
//itemElem.style.backgroundColor = '#' + Number(Math.random().toString().slice(2)).toString(16).slice(0, 6);
|
||
|
const hudElem = Object.assign(document.createElement('div'), {
|
||
|
className: 'hud',
|
||
|
innerHTML /* using nbsp to preserve vertical alignment */: `
|
||
|
<p class="status"><a target="_blank" href="${post.link}">${post.date}</a></p>
|
||
|
<p class="title"><a href="javascript:void(0);">${post.title.rendered || '...'}</a></p>
|
||
|
<p class="subtitle"><a href="javascript:void(0);">${cleanExcerpt(post.excerpt.rendered) || ' '}</a></p>
|
||
|
<button name="heart">${heartPostState(post.guid.rendered)}</button>
|
||
|
<button name="share">${icons.share}</button>
|
||
|
`,
|
||
|
});
|
||
|
hudElem.querySelector('p.title').onclick = hudElem.querySelector('p.subtitle').onclick = (function(){
|
||
|
const framesAreaElem = document.querySelector('.framesArea');
|
||
|
framesAreaElem.style.display = null;
|
||
|
framesAreaElem.innerHTML = `<div class="contentFrame">
|
||
|
<div class="header">
|
||
|
<button>❌️</button>
|
||
|
<span><a target="_blank" href="${post.link}">${post.link}</a></span>
|
||
|
</div>
|
||
|
<div class="content">${post.content.rendered}</div>
|
||
|
</div>`;
|
||
|
document.querySelector('.framesArea > .contentFrame > .header > button').onclick = (function(){
|
||
|
this.parentElement.parentElement.remove();
|
||
|
framesAreaElem.style.display = 'none';
|
||
|
});
|
||
|
|
||
|
});
|
||
|
hudElem.querySelector('button[name="heart"]').onclick = (function(){ heartPostState(post.guid.rendered, this, true) });
|
||
|
hudElem.querySelector('button[name="share"]').onclick = shareLink;
|
||
|
//const textElem = Object.assign(document.createElement('div'), {
|
||
|
// className: 'text',
|
||
|
// innerHTML: `<p>Test test</p>`,
|
||
|
//});
|
||
|
const videoElem = Object.assign(document.createElement('video'), {
|
||
|
src: post.videoUrl,
|
||
|
muted: true, loop: true, //autoplay: true,
|
||
|
onclick: (function(){
|
||
|
currentVideoElem = this;
|
||
|
if (userInteracted) {
|
||
|
this[this.paused ? 'play' : 'pause']();
|
||
|
//this.parentElement.classList[this.paused ? 'add' : 'remove']('paused');
|
||
|
} else {
|
||
|
onUserInteract();
|
||
|
}
|
||
|
}),
|
||
|
onerror: (function(){
|
||
|
// we must find a clean way to make the video autoplay if it loads
|
||
|
// after failing the first time, this is just a temporary patch
|
||
|
//this.autoplay = true;
|
||
|
this.load();
|
||
|
if (currentVideoElem === this) {
|
||
|
this.play();
|
||
|
//this.parentElement.classList[this.paused ? 'add' : 'remove']('paused');
|
||
|
}
|
||
|
}),
|
||
|
oncanplay: (function(){
|
||
|
const videoElem = this;
|
||
|
const splashElem = document.querySelector('.splash');
|
||
|
if (splashElem && (document.querySelector('.videoItem > video') === videoElem)) {
|
||
|
setTimeout((function(){
|
||
|
videoElem.currentTime = 0;
|
||
|
document.querySelector('.splash').remove();
|
||
|
videoElem.play();
|
||
|
//videoElem.parentElement.classList[videoElem.paused ? 'add' : 'remove']('paused');
|
||
|
}), 1000);
|
||
|
}
|
||
|
}),
|
||
|
});
|
||
|
videoElem.load();
|
||
|
//videoElem.play();
|
||
|
//lastVideoElem = videoElem;
|
||
|
if (!firstVideoElem) {
|
||
|
firstVideoElem = videoElem;
|
||
|
}
|
||
|
itemElem.classList.add('videoItem');
|
||
|
itemElem.appendChild(videoElem);
|
||
|
//itemElem.appendChild(textElem);
|
||
|
itemElem.appendChild(hudElem);
|
||
|
fragmentElem.appendChild(itemElem);
|
||
|
}
|
||
|
document.querySelector('.videosList').appendChild(fragmentElem);
|
||
|
scrollObserver.observe(firstVideoElem);//lastVideoElem);
|
||
|
}
|
||
|
//scrollObserver.observe(document.querySelector('.scrollLoader'));
|
||
|
addVideos();
|
||
|
//preloadCount -= 1;
|
||
|
|
||
|
// TODO fix, it's kinda bad with touch scrolling since so many events are generated;
|
||
|
// pausing should maybe only happen when the scoll is completed?
|
||
|
function onVideosScroll () {
|
||
|
//let alignedVideoElem;
|
||
|
for (const videoElem of document.querySelectorAll('.videoItem > video')) {
|
||
|
if (~~videoElem.getBoundingClientRect().y === 0) {
|
||
|
/* alignedVideoElem = */ currentVideoElem = videoElem;
|
||
|
videoElem.currentTime = 0;
|
||
|
videoElem.play();
|
||
|
if (userInteracted) {
|
||
|
videoElem.muted = false;
|
||
|
}
|
||
|
} else {
|
||
|
videoElem.pause();
|
||
|
videoElem.currentTime = 0;
|
||
|
}
|
||
|
//videoElem.parentElement.classList[videoElem.paused ? 'add' : 'remove']('paused');
|
||
|
}
|
||
|
//if (alignedVideoElem) {}
|
||
|
}
|
||
|
document.querySelector('.videosContainer').onscroll = onVideosScroll;
|
||
|
document.querySelector('.videosContainer').focus();
|
||
|
onVideosScroll();
|
||
|
|
||
|
document.querySelector('.splash').onclick = onUserInteract;
|
||
|
document.querySelector('.audioNag').onclick = (function(){
|
||
|
onUserInteract();
|
||
|
document.querySelector('.videosContainer').focus();
|
||
|
});
|
||
|
|
||
|
currentVideoElem = document.querySelector('video');
|
||
|
|
||
|
})();</script>
|
||
|
</body>
|
||
|
</html>
|