aiwebvvv / public /index.html
Vgony
revamp
e6c8ac6
raw
history blame
11.8 kB
<html>
<head>
<title>V-Pod</title>
<link rel="stylesheet" href="index.css">
<script src="/mpegts.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div
class="h-screen w-auto grid place-content-center place-items-center overflow-hidden bg-gradient-to-b from-slate-900 to-black"
>
<div x-data="app()" x-init="init()" class="container mx-auto">
<div class="flex w-full pt-16">
<video
id="videoElement"
class="aspect-video mx-auto w-auto border-4 border-slate-900/10 rounded-full"
preload="auto"
muted
autoplay
></video>
</div>
<div class="inset-x-0 bottom-0 pb-4 z-10">
<div class="container mx-auto px-2 opacity-85">
<div class="flex items-center justify-between">
<div
class="flex items-center space-x-4 text-xs focus:cursor-pointer"
>
<template x-for="(chan, index) in channels">
<div
class="text-sm capitalize truncate mr-2"
:class="chan.id === channel.id ? 'font-semibold cursor-pointer text-white' : 'text-slate-100 cursor-pointer hover:underline'"
@click="window.location = `${window.location.origin}/?channel=${chan.id}`"
x-text="chan.label"
>
<span
class="animate-ping absolute inline-flex h-3 w-3 rounded-full bg-blue-500 opacity-75"
></span>
</div>
</template>
</div>
<div class="flex-col justify-center space-y-4 items-center">
<div class="flex items-center justify-center space-x-1 text-lg">
<span>🔴</span>
<a class="text-white font-bold" x-text="'LIVE'"></a>
</div>
<div
class="flex items-center justify-center text-white opacity-80 hover:opacity-100 cursor-pointer"
x-on:click="toggleAudio()"
>
<span x-show="muted">&#x1F507;</span>
<span x-show="!muted">&#x1F508;</span>
</div>
<div
class="flex items-center justify-center text-white hover:text-white opacity-80 hover:opacity-100 cursor-pointer"
>
<a href="https://vgony.tech">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
/>
</svg>
</a>
</div>
</div>
</div>
</div>
</div>
<div
id="logo_container"
class="relative grid place-content-center place-items-center gap-2 before:bg-gradient-to-t before:from-teal-500/70 before:via-fuchsia-600 before:to-transparent before:blur-xl before:filter">
>
<h1 class="title text-6xl font-black text-teal-300">VGФЙЧ</h1>
<h2 class="cursive text-6xl font-thin text-fuchsia-500">ҒФЯԐVԐЯ</h2>
</div>
</div>
</div>
<script>
// disable analytics (we don't use VideoJS yet anyway)
window.HELP_IMPROVE_VIDEOJS = false;
</script>
<script
defer
src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"
></script>
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.2/iframeResizer.contentWindow.min.js"></script>
<!--<script src="https://vjs.zencdn.net/8.3.0/video.min.js"></script>-->
<script>
function app() {
return {
enabled: false,
channels: {
/*
legacy: {
id: 'legacy',
label: '#older',
audience: 0,
online: false,
visible: false,
url: 'https://jbilcke-hf-media-server.hf.space/live/legacy.flv',
resolution: '576x320',
model: 'zeroscope_v2_576w',
modelUrl: 'https://huggingface.co/cerspense/zeroscope_v2_576w',
},
*/
/*
hdtv: {
id: 'hdtv',
label: '#old',
audience: 0,
online: false,
visible: true,
url: 'https://jbilcke-hf-media-server.hf.space/live/hdtv.flv',
resolution: '1024x576_8FPS',
model: 'zeroscope_v2_XL',
modelUrl: 'https://huggingface.co/cerspense/zeroscope_v2_XL',
},
*/
random: {
id: "random",
label: "#random",
audience: 0,
online: false,
visible: true,
url: "https://jbilcke-hf-media-server.hf.space/live/random.flv",
resolution: "1024x576_24FPS",
model: "zeroscope_v2_XL",
modelUrl: "https://huggingface.co/cerspense/zeroscope_v2_XL",
},
comedy: {
id: "comedy",
label: "#comedy",
audience: 0,
online: false,
visible: true,
url: "https://jbilcke-hf-media-server.hf.space/live/comedy.flv",
resolution: "1024x576_24FPS",
model: "zeroscope_v2_XL",
modelUrl: "https://huggingface.co/cerspense/zeroscope_v2_XL",
},
documentary: {
id: "documentary",
label: "#documentary",
audience: 0,
online: false,
visible: true,
url: "https://jbilcke-hf-media-server.hf.space/live/documentary.flv",
resolution: "1024x576_24FPS",
model: "zeroscope_v2_XL",
modelUrl: "https://huggingface.co/cerspense/zeroscope_v2_XL",
},
},
muted: true,
initialized: false,
activityTimeout: null,
defaultChannelId: "random",
video: null,
channel: {},
wakeUp() {
this.showToolbar = true;
},
toggleAudio() {
if (this.video.muted) {
this.video.muted = false;
this.muted = false;
} else {
this.video.muted = true;
this.muted = true;
}
},
async checkAudience() {
let audience = {};
try {
const res = await fetch("/stats");
audience = await res.json();
} catch (err) {
console.log("failed to check the audience, something is wrong");
}
window.DEBUGME = Object.entries(this.channels);
this.channels = Object.entries(this.channels).reduce(
(acc, [channel, data]) => (
console.log("debug:", {
...data,
audience: audience[channel] || 0,
}),
{
...acc,
[channel]: {
...data,
audience: audience[channel] || 0,
},
}
),
{}
);
this.channel = this.channels[this.channel.id];
},
fullscreen() {
if (this.video.requestFullscreen) {
this.video.requestFullscreen();
} else if (this.video.mozRequestFullScreen) {
this.video.mozRequestFullScreen();
} else if (this.video.webkitRequestFullscreen) {
this.video.webkitRequestFullscreen();
} else if (this.video.msRequestFullscreen) {
this.video.msRequestFullscreen();
}
},
init() {
if (this.initialized) {
console.log("already initialized");
return;
}
this.initialized = true;
console.log("initializing..");
const urlParams = new URLSearchParams(window.location.search);
const requestedChannelId = `${
urlParams.get("channel") || "random"
}`;
this.enabled = true;
// this.enabled = `${urlParams.get('beta') || 'false'}` === 'true'
if (!this.enabled) {
return;
}
this.video = document.getElementById("videoElement");
const defaultChannel = this.channels[this.defaultChannelId];
this.channel = this.channels[requestedChannelId] || defaultChannel;
console.log(`Selected channel: ${this.channel.label}`);
console.log(`Stream URL: ${this.channel.url}`);
const handleActivity = () => {
this.wakeUp();
};
handleActivity();
this.checkAudience();
setInterval(() => {
this.checkAudience();
}, 1000);
// detect mute/unmute events
this.video.addEventListener("mute", () => {
this.muted = true;
});
this.video.addEventListener("unmute", () => {
this.muted = false;
});
// as a bonus, we also allow fullscreen on double click
this.video.addEventListener("dblclick", () => {
this.fullscreen();
});
// some devices such as the iPhone don't support MSE Live Playback
if (mpegts.getFeatureList().mseLivePlayback) {
var player = mpegts.createPlayer({
type: "flv", // could also be mpegts, m2ts, flv
isLive: true,
url: this.channel.url,
});
player.attachMediaElement(this.video);
player.on(mpegts.Events.ERROR, function (err) {
console.log("got an error:", err);
if (err.type === mpegts.ErrorTypes.NETWORK_ERROR) {
console.log("Network error");
}
});
player.load();
// due to an issue with our stream when the FFMPEG playlist ends,
// the stream gets interrupted for ~1sec, which causes the frontend to hangs up
// the following code tries to restart the page when that happens, but in the long term
// we should fix the issue on the server side (fix our FFMPEG bash script)
this.video.addEventListener(
"ended",
function () {
console.log("Stream ended, trying to reload...");
setTimeout(() => {
console.log("Reloading the page..");
// Unloading and loading the source again isn't enough it seems
// player.unload()
// player.load()
window.location.reload();
}, 1200);
},
false
);
// Handle autoplay restrictions.
let promise = this.video.play();
if (promise !== undefined) {
this.video.addEventListener("click", function () {
this.video.play();
});
}
player.play();
}
},
};
}
</script>
</body>
</html>