Compare commits
10
Commits
457dbfcac5
...
cf86e01d15
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf86e01d15 | ||
|
|
140e1bf792 | ||
|
|
6f92063d19 | ||
|
|
756e2eb022 | ||
|
|
d83801d787 | ||
|
|
b01e0d6a6c | ||
|
|
34753216ff | ||
|
|
a591b82bf0 | ||
|
|
d6bbd33e0c | ||
|
|
8afbe018b1 |
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"useTabs": false,
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"proseWrap": "always"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# restream viewer
|
||||
|
||||
HLS web player with automatic mirror selection and view counting. Hosted on
|
||||
Cloudflare Workers with Durable Objects.
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "player-cf",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20230628.0",
|
||||
"typescript": "^5.1.6",
|
||||
"wrangler": "4"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "wrangler dev",
|
||||
"deploy": "wrangler publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cloudflare/kv-asset-handler": "^0.3.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
// @ts-ignore
|
||||
import manifestJSON from '__STATIC_CONTENT_MANIFEST';
|
||||
import { getAssetFromKV } from '@cloudflare/kv-asset-handler';
|
||||
const assetManifest = JSON.parse(manifestJSON);
|
||||
|
||||
export interface Env {
|
||||
VIEW_COUNTER: DurableObjectNamespace;
|
||||
__STATIC_CONTENT: KVNamespace;
|
||||
CONFIG_UPSTREAM: string;
|
||||
}
|
||||
|
||||
type ViewDetails = {
|
||||
mirror: string;
|
||||
lastActive: number;
|
||||
};
|
||||
|
||||
type Viewers = { [key: string]: ViewDetails };
|
||||
|
||||
export class ViewCounter implements DurableObject {
|
||||
state: DurableObjectState;
|
||||
|
||||
constructor(state: DurableObjectState, env: any) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
aggregateViews(viewers: Viewers) {
|
||||
const byMirror: { [key: string]: number } = {};
|
||||
for (const { mirror } of Object.values(viewers)) {
|
||||
byMirror[mirror] = (byMirror[mirror] ?? 0) + 1;
|
||||
}
|
||||
return byMirror;
|
||||
}
|
||||
|
||||
async fetch(request: Request): Promise<Response> {
|
||||
const ip = request.headers.get('cf-connecting-ip');
|
||||
const url = new URL(request.url);
|
||||
|
||||
if (!ip) {
|
||||
return new Response('No IP found', { status: 400 });
|
||||
}
|
||||
|
||||
// Get the viewers object
|
||||
const viewers = ((await this.state.storage.get('viewers')) ??
|
||||
{}) as Viewers;
|
||||
|
||||
// Delete old viewers
|
||||
for (const [ip, { lastActive }] of Object.entries(viewers)) {
|
||||
if (lastActive < Date.now() - 1000 * 10) {
|
||||
delete viewers[ip];
|
||||
}
|
||||
}
|
||||
|
||||
if (request.method === 'POST' && url.pathname === '/viewcount') {
|
||||
const body = (await request.json()) as any;
|
||||
|
||||
// Register the view
|
||||
const mirror = body.mirror;
|
||||
const lastActive = Date.now();
|
||||
viewers[ip] = { mirror, lastActive };
|
||||
|
||||
// Save the viewers object
|
||||
await this.state.storage.put('viewers', viewers);
|
||||
|
||||
const by_mirror = this.aggregateViews(viewers);
|
||||
const total_count = Array.from(Object.values(by_mirror)).reduce(
|
||||
(a, b) => a + b,
|
||||
0
|
||||
);
|
||||
|
||||
return new Response(JSON.stringify({ total_count, by_mirror }), {
|
||||
headers: { 'content-type': 'application/json' },
|
||||
});
|
||||
} else {
|
||||
// Save the viewers object (after deleting old viewers)
|
||||
await this.state.storage.put('viewers', viewers);
|
||||
}
|
||||
|
||||
if (request.method === 'GET' && url.pathname === '/metrics') {
|
||||
return new Response(
|
||||
Object.entries(this.aggregateViews(viewers))
|
||||
.map(
|
||||
([mirror, count]) =>
|
||||
`restream_viewers_count{mirror="${mirror}"} ${count}`
|
||||
)
|
||||
.join('\n'),
|
||||
{
|
||||
headers: { 'content-type': 'text/plain' },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return new Response('Not found', { status: 404 });
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Env,
|
||||
ctx: ExecutionContext
|
||||
): Promise<Response> {
|
||||
const url = new URL(request.url);
|
||||
|
||||
// https redirect
|
||||
if (url.protocol === 'http:') {
|
||||
url.protocol = 'https:';
|
||||
return new Response(null, {
|
||||
status: 308,
|
||||
headers: { Location: url.toString() },
|
||||
});
|
||||
}
|
||||
|
||||
// routes to be handled by the view counter
|
||||
if (['/viewcount', '/metrics'].includes(url.pathname)) {
|
||||
const viewCounter = env.VIEW_COUNTER.get(
|
||||
env.VIEW_COUNTER.idFromName('viewcounter')
|
||||
);
|
||||
return viewCounter.fetch(request);
|
||||
}
|
||||
|
||||
if (url.pathname === '/config') {
|
||||
return fetch(env.CONFIG_UPSTREAM, {
|
||||
cf: {
|
||||
cacheEverything: true,
|
||||
cacheTtl: 60 * 5, // 5 minutes
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Handle KV assets
|
||||
try {
|
||||
return await getAssetFromKV(
|
||||
{
|
||||
request,
|
||||
waitUntil: ctx.waitUntil.bind(ctx),
|
||||
},
|
||||
{
|
||||
ASSET_NAMESPACE: env.__STATIC_CONTENT,
|
||||
ASSET_MANIFEST: assetManifest,
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
let pathname = new URL(request.url).pathname;
|
||||
return new Response(`"${pathname}" not found`, {
|
||||
status: 404,
|
||||
statusText: 'not found',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Restream</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<link rel="stylesheet" href="./player.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/video.js@7.18.1/dist/video-js.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/videojs-hls-quality-selector@1.1.4/dist/videojs-hls-quality-selector.css"
|
||||
/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/video.js@7.18.1/dist/video.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/videojs-contrib-quality-levels@2.1.0/dist/videojs-contrib-quality-levels.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/videojs-hls-quality-selector@1.1.4/dist/videojs-hls-quality-selector.min.js"></script>
|
||||
<script src="./player.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1><strong>Restream</strong> | Ahoy!</h1>
|
||||
<select id="mirror-select">
|
||||
<option value="">Loading mirrors...</option>
|
||||
</select>
|
||||
<a id="mirror-link" href="#"></a>
|
||||
<div id="viewer-count">
|
||||
<span id="viewer-count-value">0</span> viewers
|
||||
</div>
|
||||
</header>
|
||||
<div id="mirror-popup" style="transition: all 0.2s">
|
||||
<div class="popup-backdrop"></div>
|
||||
<div
|
||||
class="popup-box"
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
"
|
||||
>
|
||||
<div>
|
||||
<span class="loader"></span>
|
||||
</div>
|
||||
<div>
|
||||
<h1 style="font-weight: bold; margin-bottom: 0.2rem">Please wait</h1>
|
||||
<p style="color: #bbb">
|
||||
Selecting a mirror... <span id="mirror-load-progress"></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<video-js
|
||||
controls
|
||||
autoplay
|
||||
preload="auto"
|
||||
id="video"
|
||||
class="vjs-default-skin vjs-big-play-centered"
|
||||
>
|
||||
</video-js>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,111 @@
|
||||
/* http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
|
||||
/* prettier-ignore */
|
||||
@media (min-width:1px) { html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } }
|
||||
|
||||
/**
|
||||
* Player styles
|
||||
*/
|
||||
|
||||
body,
|
||||
html {
|
||||
height: 100vh;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: #333;
|
||||
padding: 0.5em;
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
header {
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
header {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a,
|
||||
a:link,
|
||||
a:visited {
|
||||
color: #5bd9ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover,
|
||||
a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.popup-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
z-index: 99;
|
||||
}
|
||||
.popup-box {
|
||||
background-color: #333;
|
||||
padding: 1.5em 2em;
|
||||
border-radius: 0.5em;
|
||||
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#viewer-count {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: black;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 5px solid #fff;
|
||||
border-bottom-color: #ff3d00;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
animation: rotation 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
(() => {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Upstream
|
||||
* @property {string} region - The region of the upstream.
|
||||
* @property {string} url - The URL of the upstream.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} RestreamConfig
|
||||
* @property {Upstream[]} upstreams - Array of upstreams.
|
||||
* @property {string} playlist - The playlist URL.
|
||||
*/
|
||||
|
||||
/** @type {RestreamConfig} */
|
||||
let restream_config = {};
|
||||
|
||||
// Utility functions
|
||||
const fetchWithTimeout = async (resource, options = {}) => {
|
||||
const { timeout = 30000 } = options;
|
||||
|
||||
const controller = new AbortController();
|
||||
const id = setTimeout(() => controller.abort(), timeout);
|
||||
const response = await fetch(resource, {
|
||||
...options,
|
||||
signal: controller.signal,
|
||||
});
|
||||
clearTimeout(id);
|
||||
return response;
|
||||
};
|
||||
|
||||
// Measure the average time it takes to get a response from the url
|
||||
const ping = async (url) => {
|
||||
const start = performance.now();
|
||||
await fetchWithTimeout(url, {
|
||||
timeout: 1000,
|
||||
mode: 'cors',
|
||||
});
|
||||
const end = performance.now();
|
||||
return end - start;
|
||||
};
|
||||
|
||||
// Async sleep
|
||||
const sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
const measureLatency = async (url, count, gap = 100) => {
|
||||
const results = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const latency = await ping(url).catch(() => null);
|
||||
if (latency) results.push(latency);
|
||||
await sleep(gap);
|
||||
}
|
||||
|
||||
if (results.length === 0) return null;
|
||||
return results.reduce((a, b) => a + b, 0) / count;
|
||||
};
|
||||
|
||||
const measureUpstreamLatency = async (upstream, n = 3) => {
|
||||
const playlistURL = upstream.url + restream_config.playlist;
|
||||
const latency = await measureLatency(playlistURL, n);
|
||||
upstream.latency = latency;
|
||||
updateMirrorList();
|
||||
};
|
||||
|
||||
const updateMirrorList = () => {
|
||||
const mirrorSelect = document.getElementById('mirror-select');
|
||||
const current = mirrorSelect.value;
|
||||
|
||||
// Clear the current list
|
||||
while (mirrorSelect.firstChild) {
|
||||
mirrorSelect.removeChild(mirrorSelect.firstChild);
|
||||
}
|
||||
|
||||
// Add each upstream server to the list
|
||||
for (const upstream of restream_config.upstreams) {
|
||||
const option = document.createElement('option');
|
||||
option.value = upstream.url;
|
||||
option.text =
|
||||
`[${upstream.region}] ${upstream.url} (` +
|
||||
[
|
||||
typeof upstream.latency === 'number'
|
||||
? Math.floor(upstream.latency) + 'ms'
|
||||
: 'error',
|
||||
(upstream.active_viewers || '0') + ' viewers',
|
||||
].join(', ') +
|
||||
')';
|
||||
mirrorSelect.add(option);
|
||||
}
|
||||
|
||||
// Restore the previous selection
|
||||
if (current) mirrorSelect.value = current;
|
||||
};
|
||||
|
||||
const reloadVideo = () => {
|
||||
const mirrorSelect = document.getElementById('mirror-select');
|
||||
const mirrorLink = document.getElementById('mirror-link');
|
||||
const playlistURL = mirrorSelect.value + restream_config.playlist;
|
||||
|
||||
if (restream_config.activeURL === playlistURL) return;
|
||||
|
||||
console.log('Reloading video from', playlistURL);
|
||||
if (typeof window.player === 'undefined') {
|
||||
window.player = videojs('video', {
|
||||
liveui: true,
|
||||
liveTracker: {
|
||||
liveTolerance: 5,
|
||||
},
|
||||
});
|
||||
window.player.volume(0.5);
|
||||
}
|
||||
window.player.src({
|
||||
src: playlistURL,
|
||||
type: 'application/x-mpegURL',
|
||||
});
|
||||
window.player.play();
|
||||
try {
|
||||
window.player.hlsQualitySelector({
|
||||
displayCurrentQuality: true,
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
restream_config.activeURL = playlistURL;
|
||||
mirrorLink.href = playlistURL;
|
||||
mirrorLink.innerText = '[m3u8]';
|
||||
};
|
||||
|
||||
const doViewCount = async () => {
|
||||
const viewCount = document.getElementById('viewer-count-value');
|
||||
|
||||
const activeMirrorUrl = document.getElementById('mirror-select').value;
|
||||
if (!activeMirrorUrl) {
|
||||
await sleep(1000);
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetchWithTimeout('/viewcount', {
|
||||
method: 'POST',
|
||||
timeout: 1000,
|
||||
mode: 'cors',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ mirror: activeMirrorUrl }),
|
||||
});
|
||||
const { total_count, by_mirror } = await response.json();
|
||||
viewCount.innerText = total_count;
|
||||
|
||||
restream_config.upstreams.forEach((stream) => {
|
||||
const { url } = stream;
|
||||
stream.active_viewers = by_mirror[url] ?? 0;
|
||||
});
|
||||
|
||||
updateMirrorList();
|
||||
};
|
||||
|
||||
const viewCountLoop = async () => {
|
||||
while (true) {
|
||||
try {
|
||||
await doViewCount();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
await sleep(5000);
|
||||
}
|
||||
};
|
||||
|
||||
const latencyMeasurementLoop = async () => {
|
||||
while (true) {
|
||||
try {
|
||||
for (const upstream of restream_config.upstreams) {
|
||||
await measureUpstreamLatency(upstream, 1);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
await sleep(10000);
|
||||
}
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
const mirrorSelect = document.getElementById('mirror-select');
|
||||
const mirrorPopup = document.getElementById('mirror-popup');
|
||||
|
||||
// Fetch stream configuration
|
||||
restream_config = await fetch('/config').then((r) => r.json());
|
||||
const { upstreams } = restream_config;
|
||||
|
||||
// Set up event listeners
|
||||
mirrorSelect.addEventListener('change', () => reloadVideo());
|
||||
|
||||
// Measure latency
|
||||
await Promise.all(
|
||||
upstreams.map((upstream) => measureUpstreamLatency(upstream))
|
||||
);
|
||||
|
||||
// Choose the fastest upstream server
|
||||
const upstream = upstreams
|
||||
.filter((upstream) => typeof upstream.latency === 'number')
|
||||
.sort((a, b) => a.latency - b.latency)[0];
|
||||
|
||||
if (!upstream) {
|
||||
document.querySelector('#mirror-popup .popup-box').innerText =
|
||||
'No upstream servers found';
|
||||
return;
|
||||
}
|
||||
|
||||
mirrorSelect.value = upstream.url;
|
||||
reloadVideo();
|
||||
|
||||
// Destroy the popup
|
||||
mirrorPopup.style.opacity = 0;
|
||||
mirrorPopup.style.pointerEvents = 'none';
|
||||
setTimeout(() => {
|
||||
mirrorPopup.remove();
|
||||
}, 1000);
|
||||
|
||||
// Init loops
|
||||
viewCountLoop();
|
||||
latencyMeasurementLoop();
|
||||
};
|
||||
|
||||
if (document.readyState === 'loading')
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
else init();
|
||||
})();
|
||||
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
"lib": [
|
||||
"es2021"
|
||||
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
|
||||
"jsx": "react" /* Specify what JSX code is generated. */,
|
||||
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
|
||||
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
|
||||
/* Modules */
|
||||
"module": "es2022" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
|
||||
"types": [
|
||||
"@cloudflare/workers-types"
|
||||
] /* Specify type package names to be included without being referenced in a source file. */,
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
"resolveJsonModule": true /* Enable importing .json files */,
|
||||
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
"allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */,
|
||||
"checkJs": false /* Enable error reporting in type-checked JavaScript files. */,
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
|
||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
"noEmit": true /* Disable emitting files from a compilation. */,
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
"isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */,
|
||||
"allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */,
|
||||
// "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
|
||||
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
name = "player-cf"
|
||||
main = "src/index.ts"
|
||||
compatibility_date = "2023-07-09"
|
||||
|
||||
[site]
|
||||
bucket = "./static"
|
||||
|
||||
[durable_objects]
|
||||
bindings = [{ name = "VIEW_COUNTER", class_name = "ViewCounter" }]
|
||||
|
||||
[[migrations]]
|
||||
tag = "v1"
|
||||
new_sqlite_classes = ["ViewCounter"]
|
||||
|
||||
[vars]
|
||||
CONFIG_UPSTREAM = "https://pastebin.com/raw/mngqMS0g"
|
||||
@@ -0,0 +1,653 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@cloudflare/kv-asset-handler@0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.0.tgz"
|
||||
integrity sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==
|
||||
dependencies:
|
||||
mime "^3.0.0"
|
||||
|
||||
"@cloudflare/kv-asset-handler@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.0.tgz"
|
||||
integrity sha512-9CB/MKf/wdvbfkUdfrj+OkEwZ5b7rws0eogJ4293h+7b6KX5toPwym+VQKmILafNB9YiehqY0DlNrDcDhdWHSQ==
|
||||
dependencies:
|
||||
mime "^3.0.0"
|
||||
|
||||
"@cloudflare/unenv-preset@2.6.2":
|
||||
version "2.6.2"
|
||||
resolved "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.6.2.tgz"
|
||||
integrity sha512-C7/tW7Qy+wGOCmHXu7xpP1TF3uIhRoi7zVY7dmu/SOSGjPilK+lSQ2lIRILulZsT467ZJNlI0jBxMbd8LzkGRg==
|
||||
|
||||
"@cloudflare/workerd-darwin-64@1.20250816.0":
|
||||
version "1.20250816.0"
|
||||
resolved "https://registry.yarnpkg.com/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250816.0.tgz#de026c259e0902c5f372069fdf77b159702e294f"
|
||||
integrity sha512-yN1Rga4ufTdrJPCP4gEqfB47i1lWi3teY5IoeQbUuKnjnCtm4pZvXur526JzCmaw60Jx+AEWf5tizdwRd5hHBQ==
|
||||
|
||||
"@cloudflare/workerd-darwin-arm64@1.20250816.0":
|
||||
version "1.20250816.0"
|
||||
resolved "https://registry.yarnpkg.com/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250816.0.tgz#d17be81ab7b8f66f5057e87c7bb42b2eea8a92bb"
|
||||
integrity sha512-WyKPMQhbU+TTf4uDz3SA7ZObspg7WzyJMv/7J4grSddpdx2A4Y4SfPu3wsZleAOIMOAEVi0A1sYDhdltKM7Mxg==
|
||||
|
||||
"@cloudflare/workerd-linux-64@1.20250816.0":
|
||||
version "1.20250816.0"
|
||||
resolved "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250816.0.tgz"
|
||||
integrity sha512-NWHOuFnVBaPRhLHw8kjPO9GJmc2P/CTYbnNlNm0EThyi57o/oDx0ldWLJqEHlrdEPOw7zEVGBqM/6M+V9agC6w==
|
||||
|
||||
"@cloudflare/workerd-linux-arm64@1.20250816.0":
|
||||
version "1.20250816.0"
|
||||
resolved "https://registry.yarnpkg.com/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250816.0.tgz#e6c680ba9c290a6179b6c9c08f5a6d259f86821e"
|
||||
integrity sha512-FR+/yhaWs7FhfC3GKsM3+usQVrGEweJ9qyh7p+R6HNwnobgKr/h5ATWvJ4obGJF6ZHHodgSe+gOSYR7fkJ1xAQ==
|
||||
|
||||
"@cloudflare/workerd-windows-64@1.20250816.0":
|
||||
version "1.20250816.0"
|
||||
resolved "https://registry.yarnpkg.com/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250816.0.tgz#7160e6d51f29c248dc8139f7245efd1f2f0786f1"
|
||||
integrity sha512-0lqClj2UMhFa8tCBiiX7Zhd5Bjp0V+X8oNBG6V6WsR9p9/HlIHAGgwRAM7aYkyG+8KC8xlbC89O2AXUXLpHx0g==
|
||||
|
||||
"@cloudflare/workers-types@^4.20230628.0":
|
||||
version "4.20250819.0"
|
||||
resolved "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20250819.0.tgz"
|
||||
integrity sha512-TGghrtaQzT2k71gdiUOxwwt3owni1rWX3+BBTk1K/H0vmsinwEJsGmEJRdvIuQO72Davtfz9u6LBbR1uNoE1Qw==
|
||||
|
||||
"@cspotcode/source-map-support@0.8.1":
|
||||
version "0.8.1"
|
||||
resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz"
|
||||
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
|
||||
dependencies:
|
||||
"@jridgewell/trace-mapping" "0.3.9"
|
||||
|
||||
"@emnapi/runtime@^1.2.0":
|
||||
version "1.4.5"
|
||||
resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.5.tgz#c67710d0661070f38418b6474584f159de38aba9"
|
||||
integrity sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@esbuild/aix-ppc64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz#830d6476cbbca0c005136af07303646b419f1162"
|
||||
integrity sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==
|
||||
|
||||
"@esbuild/android-arm64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz#d11d4fc299224e729e2190cacadbcc00e7a9fd67"
|
||||
integrity sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==
|
||||
|
||||
"@esbuild/android-arm@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.4.tgz#5660bd25080553dd2a28438f2a401a29959bd9b1"
|
||||
integrity sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==
|
||||
|
||||
"@esbuild/android-x64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.4.tgz#18ddde705bf984e8cd9efec54e199ac18bc7bee1"
|
||||
integrity sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==
|
||||
|
||||
"@esbuild/darwin-arm64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz#b0b7fb55db8fc6f5de5a0207ae986eb9c4766e67"
|
||||
integrity sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==
|
||||
|
||||
"@esbuild/darwin-x64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz#e6813fdeba0bba356cb350a4b80543fbe66bf26f"
|
||||
integrity sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz#dc11a73d3ccdc308567b908b43c6698e850759be"
|
||||
integrity sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==
|
||||
|
||||
"@esbuild/freebsd-x64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz#91da08db8bd1bff5f31924c57a81dab26e93a143"
|
||||
integrity sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==
|
||||
|
||||
"@esbuild/linux-arm64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz#efc15e45c945a082708f9a9f73bfa8d4db49728a"
|
||||
integrity sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==
|
||||
|
||||
"@esbuild/linux-arm@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz#9b93c3e54ac49a2ede6f906e705d5d906f6db9e8"
|
||||
integrity sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==
|
||||
|
||||
"@esbuild/linux-ia32@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz#be8ef2c3e1d99fca2d25c416b297d00360623596"
|
||||
integrity sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==
|
||||
|
||||
"@esbuild/linux-loong64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz#b0840a2707c3fc02eec288d3f9defa3827cd7a87"
|
||||
integrity sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==
|
||||
|
||||
"@esbuild/linux-mips64el@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz#2a198e5a458c9f0e75881a4e63d26ba0cf9df39f"
|
||||
integrity sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==
|
||||
|
||||
"@esbuild/linux-ppc64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz#64f4ae0b923d7dd72fb860b9b22edb42007cf8f5"
|
||||
integrity sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==
|
||||
|
||||
"@esbuild/linux-riscv64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz#fb2844b11fdddd39e29d291c7cf80f99b0d5158d"
|
||||
integrity sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==
|
||||
|
||||
"@esbuild/linux-s390x@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz#1466876e0aa3560c7673e63fdebc8278707bc750"
|
||||
integrity sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==
|
||||
|
||||
"@esbuild/linux-x64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz"
|
||||
integrity sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==
|
||||
|
||||
"@esbuild/netbsd-arm64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz#02e483fbcbe3f18f0b02612a941b77be76c111a4"
|
||||
integrity sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==
|
||||
|
||||
"@esbuild/netbsd-x64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz#ec401fb0b1ed0ac01d978564c5fc8634ed1dc2ed"
|
||||
integrity sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==
|
||||
|
||||
"@esbuild/openbsd-arm64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz#f272c2f41cfea1d91b93d487a51b5c5ca7a8c8c4"
|
||||
integrity sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==
|
||||
|
||||
"@esbuild/openbsd-x64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz#2e25950bc10fa9db1e5c868e3d50c44f7c150fd7"
|
||||
integrity sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==
|
||||
|
||||
"@esbuild/sunos-x64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz#cd596fa65a67b3b7adc5ecd52d9f5733832e1abd"
|
||||
integrity sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==
|
||||
|
||||
"@esbuild/win32-arm64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz#b4dbcb57b21eeaf8331e424c3999b89d8951dc88"
|
||||
integrity sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==
|
||||
|
||||
"@esbuild/win32-ia32@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz#410842e5d66d4ece1757634e297a87635eb82f7a"
|
||||
integrity sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==
|
||||
|
||||
"@esbuild/win32-x64@0.25.4":
|
||||
version "0.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz#0b17ec8a70b2385827d52314c1253160a0b9bacc"
|
||||
integrity sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==
|
||||
|
||||
"@img/sharp-darwin-arm64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz#ef5b5a07862805f1e8145a377c8ba6e98813ca08"
|
||||
integrity sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-darwin-arm64" "1.0.4"
|
||||
|
||||
"@img/sharp-darwin-x64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz#e03d3451cd9e664faa72948cc70a403ea4063d61"
|
||||
integrity sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-darwin-x64" "1.0.4"
|
||||
|
||||
"@img/sharp-libvips-darwin-arm64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz#447c5026700c01a993c7804eb8af5f6e9868c07f"
|
||||
integrity sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==
|
||||
|
||||
"@img/sharp-libvips-darwin-x64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz#e0456f8f7c623f9dbfbdc77383caa72281d86062"
|
||||
integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==
|
||||
|
||||
"@img/sharp-libvips-linux-arm64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz#979b1c66c9a91f7ff2893556ef267f90ebe51704"
|
||||
integrity sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==
|
||||
|
||||
"@img/sharp-libvips-linux-arm@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz#99f922d4e15216ec205dcb6891b721bfd2884197"
|
||||
integrity sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==
|
||||
|
||||
"@img/sharp-libvips-linux-s390x@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz#f8a5eb1f374a082f72b3f45e2fb25b8118a8a5ce"
|
||||
integrity sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==
|
||||
|
||||
"@img/sharp-libvips-linux-x64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz"
|
||||
integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-arm64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz#166778da0f48dd2bded1fa3033cee6b588f0d5d5"
|
||||
integrity sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-x64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz#93794e4d7720b077fcad3e02982f2f1c246751ff"
|
||||
integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==
|
||||
|
||||
"@img/sharp-linux-arm64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz#edb0697e7a8279c9fc829a60fc35644c4839bb22"
|
||||
integrity sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-arm64" "1.0.4"
|
||||
|
||||
"@img/sharp-linux-arm@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz#422c1a352e7b5832842577dc51602bcd5b6f5eff"
|
||||
integrity sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-arm" "1.0.5"
|
||||
|
||||
"@img/sharp-linux-s390x@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz#f5c077926b48e97e4a04d004dfaf175972059667"
|
||||
integrity sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-s390x" "1.0.4"
|
||||
|
||||
"@img/sharp-linux-x64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz"
|
||||
integrity sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-x64" "1.0.4"
|
||||
|
||||
"@img/sharp-linuxmusl-arm64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz#252975b915894fb315af5deea174651e208d3d6b"
|
||||
integrity sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linuxmusl-arm64" "1.0.4"
|
||||
|
||||
"@img/sharp-linuxmusl-x64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz#3f4609ac5d8ef8ec7dadee80b560961a60fd4f48"
|
||||
integrity sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linuxmusl-x64" "1.0.4"
|
||||
|
||||
"@img/sharp-wasm32@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz#6f44f3283069d935bb5ca5813153572f3e6f61a1"
|
||||
integrity sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==
|
||||
dependencies:
|
||||
"@emnapi/runtime" "^1.2.0"
|
||||
|
||||
"@img/sharp-win32-ia32@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz#1a0c839a40c5351e9885628c85f2e5dfd02b52a9"
|
||||
integrity sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==
|
||||
|
||||
"@img/sharp-win32-x64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz#56f00962ff0c4e0eb93d34a047d29fa995e3e342"
|
||||
integrity sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==
|
||||
|
||||
"@jridgewell/resolve-uri@^3.0.3":
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz"
|
||||
integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10":
|
||||
version "1.5.5"
|
||||
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz"
|
||||
integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==
|
||||
|
||||
"@jridgewell/trace-mapping@0.3.9":
|
||||
version "0.3.9"
|
||||
resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz"
|
||||
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@poppinss/colors@^4.1.5":
|
||||
version "4.1.5"
|
||||
resolved "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.5.tgz"
|
||||
integrity sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==
|
||||
dependencies:
|
||||
kleur "^4.1.5"
|
||||
|
||||
"@poppinss/dumper@^0.6.4":
|
||||
version "0.6.4"
|
||||
resolved "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.4.tgz"
|
||||
integrity sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ==
|
||||
dependencies:
|
||||
"@poppinss/colors" "^4.1.5"
|
||||
"@sindresorhus/is" "^7.0.2"
|
||||
supports-color "^10.0.0"
|
||||
|
||||
"@poppinss/exception@^1.2.2":
|
||||
version "1.2.2"
|
||||
resolved "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.2.tgz"
|
||||
integrity sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==
|
||||
|
||||
"@sindresorhus/is@^7.0.2":
|
||||
version "7.0.2"
|
||||
resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.2.tgz"
|
||||
integrity sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw==
|
||||
|
||||
"@speed-highlight/core@^1.2.7":
|
||||
version "1.2.7"
|
||||
resolved "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.7.tgz"
|
||||
integrity sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==
|
||||
|
||||
acorn-walk@8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz"
|
||||
integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==
|
||||
|
||||
acorn@8.14.0:
|
||||
version "8.14.0"
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz"
|
||||
integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
|
||||
|
||||
blake3-wasm@2.1.5:
|
||||
version "2.1.5"
|
||||
resolved "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz"
|
||||
integrity sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
|
||||
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
|
||||
dependencies:
|
||||
color-name "~1.1.4"
|
||||
|
||||
color-name@^1.0.0, color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-string@^1.9.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz"
|
||||
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
|
||||
dependencies:
|
||||
color-name "^1.0.0"
|
||||
simple-swizzle "^0.2.2"
|
||||
|
||||
color@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.npmjs.org/color/-/color-4.2.3.tgz"
|
||||
integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
color-string "^1.9.0"
|
||||
|
||||
cookie@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz"
|
||||
integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==
|
||||
|
||||
defu@^6.1.4:
|
||||
version "6.1.4"
|
||||
resolved "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz"
|
||||
integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==
|
||||
|
||||
detect-libc@^2.0.3:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz"
|
||||
integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==
|
||||
|
||||
error-stack-parser-es@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz"
|
||||
integrity sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==
|
||||
|
||||
esbuild@0.25.4:
|
||||
version "0.25.4"
|
||||
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz"
|
||||
integrity sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==
|
||||
optionalDependencies:
|
||||
"@esbuild/aix-ppc64" "0.25.4"
|
||||
"@esbuild/android-arm" "0.25.4"
|
||||
"@esbuild/android-arm64" "0.25.4"
|
||||
"@esbuild/android-x64" "0.25.4"
|
||||
"@esbuild/darwin-arm64" "0.25.4"
|
||||
"@esbuild/darwin-x64" "0.25.4"
|
||||
"@esbuild/freebsd-arm64" "0.25.4"
|
||||
"@esbuild/freebsd-x64" "0.25.4"
|
||||
"@esbuild/linux-arm" "0.25.4"
|
||||
"@esbuild/linux-arm64" "0.25.4"
|
||||
"@esbuild/linux-ia32" "0.25.4"
|
||||
"@esbuild/linux-loong64" "0.25.4"
|
||||
"@esbuild/linux-mips64el" "0.25.4"
|
||||
"@esbuild/linux-ppc64" "0.25.4"
|
||||
"@esbuild/linux-riscv64" "0.25.4"
|
||||
"@esbuild/linux-s390x" "0.25.4"
|
||||
"@esbuild/linux-x64" "0.25.4"
|
||||
"@esbuild/netbsd-arm64" "0.25.4"
|
||||
"@esbuild/netbsd-x64" "0.25.4"
|
||||
"@esbuild/openbsd-arm64" "0.25.4"
|
||||
"@esbuild/openbsd-x64" "0.25.4"
|
||||
"@esbuild/sunos-x64" "0.25.4"
|
||||
"@esbuild/win32-arm64" "0.25.4"
|
||||
"@esbuild/win32-ia32" "0.25.4"
|
||||
"@esbuild/win32-x64" "0.25.4"
|
||||
|
||||
exit-hook@2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz"
|
||||
integrity sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==
|
||||
|
||||
exsolve@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz"
|
||||
integrity sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==
|
||||
|
||||
fsevents@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
|
||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||
|
||||
glob-to-regexp@0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz"
|
||||
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
|
||||
|
||||
is-arrayish@^0.3.1:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz"
|
||||
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
|
||||
|
||||
kleur@^4.1.5:
|
||||
version "4.1.5"
|
||||
resolved "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz"
|
||||
integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==
|
||||
|
||||
mime@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz"
|
||||
integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==
|
||||
|
||||
miniflare@4.20250816.0:
|
||||
version "4.20250816.0"
|
||||
resolved "https://registry.npmjs.org/miniflare/-/miniflare-4.20250816.0.tgz"
|
||||
integrity sha512-HuakGvmsU8aC60wsHP7Su+BgJFly1GmKbmbR/nqIz0Xlk6wcd/pp3vZ7jtbT3unf+aeBOlEO/CzcUb8xFsJLdA==
|
||||
dependencies:
|
||||
"@cspotcode/source-map-support" "0.8.1"
|
||||
acorn "8.14.0"
|
||||
acorn-walk "8.3.2"
|
||||
exit-hook "2.2.1"
|
||||
glob-to-regexp "0.4.1"
|
||||
sharp "^0.33.5"
|
||||
stoppable "1.1.0"
|
||||
undici "^7.10.0"
|
||||
workerd "1.20250816.0"
|
||||
ws "8.18.0"
|
||||
youch "4.1.0-beta.10"
|
||||
zod "3.22.3"
|
||||
|
||||
ohash@^2.0.11:
|
||||
version "2.0.11"
|
||||
resolved "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz"
|
||||
integrity sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==
|
||||
|
||||
path-to-regexp@6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz"
|
||||
integrity sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==
|
||||
|
||||
pathe@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz"
|
||||
integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==
|
||||
|
||||
semver@^7.6.3:
|
||||
version "7.7.2"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz"
|
||||
integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
|
||||
|
||||
sharp@^0.33.5:
|
||||
version "0.33.5"
|
||||
resolved "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz"
|
||||
integrity sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==
|
||||
dependencies:
|
||||
color "^4.2.3"
|
||||
detect-libc "^2.0.3"
|
||||
semver "^7.6.3"
|
||||
optionalDependencies:
|
||||
"@img/sharp-darwin-arm64" "0.33.5"
|
||||
"@img/sharp-darwin-x64" "0.33.5"
|
||||
"@img/sharp-libvips-darwin-arm64" "1.0.4"
|
||||
"@img/sharp-libvips-darwin-x64" "1.0.4"
|
||||
"@img/sharp-libvips-linux-arm" "1.0.5"
|
||||
"@img/sharp-libvips-linux-arm64" "1.0.4"
|
||||
"@img/sharp-libvips-linux-s390x" "1.0.4"
|
||||
"@img/sharp-libvips-linux-x64" "1.0.4"
|
||||
"@img/sharp-libvips-linuxmusl-arm64" "1.0.4"
|
||||
"@img/sharp-libvips-linuxmusl-x64" "1.0.4"
|
||||
"@img/sharp-linux-arm" "0.33.5"
|
||||
"@img/sharp-linux-arm64" "0.33.5"
|
||||
"@img/sharp-linux-s390x" "0.33.5"
|
||||
"@img/sharp-linux-x64" "0.33.5"
|
||||
"@img/sharp-linuxmusl-arm64" "0.33.5"
|
||||
"@img/sharp-linuxmusl-x64" "0.33.5"
|
||||
"@img/sharp-wasm32" "0.33.5"
|
||||
"@img/sharp-win32-ia32" "0.33.5"
|
||||
"@img/sharp-win32-x64" "0.33.5"
|
||||
|
||||
simple-swizzle@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz"
|
||||
integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
|
||||
dependencies:
|
||||
is-arrayish "^0.3.1"
|
||||
|
||||
stoppable@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz"
|
||||
integrity sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==
|
||||
|
||||
supports-color@^10.0.0:
|
||||
version "10.2.0"
|
||||
resolved "https://registry.npmjs.org/supports-color/-/supports-color-10.2.0.tgz"
|
||||
integrity sha512-5eG9FQjEjDbAlI5+kdpdyPIBMRH4GfTVDGREVupaZHmVoppknhM29b/S9BkQz7cathp85BVgRi/As3Siln7e0Q==
|
||||
|
||||
tslib@^2.4.0:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||
|
||||
typescript@^5.1.6:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz"
|
||||
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
|
||||
|
||||
ufo@^1.6.1:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz"
|
||||
integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==
|
||||
|
||||
undici@^7.10.0:
|
||||
version "7.14.0"
|
||||
resolved "https://registry.npmjs.org/undici/-/undici-7.14.0.tgz"
|
||||
integrity sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==
|
||||
|
||||
unenv@2.0.0-rc.19:
|
||||
version "2.0.0-rc.19"
|
||||
resolved "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.19.tgz"
|
||||
integrity sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA==
|
||||
dependencies:
|
||||
defu "^6.1.4"
|
||||
exsolve "^1.0.7"
|
||||
ohash "^2.0.11"
|
||||
pathe "^2.0.3"
|
||||
ufo "^1.6.1"
|
||||
|
||||
workerd@1.20250816.0:
|
||||
version "1.20250816.0"
|
||||
resolved "https://registry.npmjs.org/workerd/-/workerd-1.20250816.0.tgz"
|
||||
integrity sha512-5gIvHPE/3QVlQR1Sc1NdBkWmqWj/TSgIbY/f/qs9lhiLBw/Da+HbNBTVYGjvwYqEb3NQ+XQM4gAm5b2+JJaUJg==
|
||||
optionalDependencies:
|
||||
"@cloudflare/workerd-darwin-64" "1.20250816.0"
|
||||
"@cloudflare/workerd-darwin-arm64" "1.20250816.0"
|
||||
"@cloudflare/workerd-linux-64" "1.20250816.0"
|
||||
"@cloudflare/workerd-linux-arm64" "1.20250816.0"
|
||||
"@cloudflare/workerd-windows-64" "1.20250816.0"
|
||||
|
||||
wrangler@4:
|
||||
version "4.31.0"
|
||||
resolved "https://registry.yarnpkg.com/wrangler/-/wrangler-4.31.0.tgz#728c0d5f5cc1b0014493ee00e5876cbce3cd4e1f"
|
||||
integrity sha512-blb8NfA4BGscvSzvLm2mEQRuUTmaMCiglkqHiR3EIque78UXG39xxVtFXlKhK32qaVvGI7ejdM//HC9plVPO3w==
|
||||
dependencies:
|
||||
"@cloudflare/kv-asset-handler" "0.4.0"
|
||||
"@cloudflare/unenv-preset" "2.6.2"
|
||||
blake3-wasm "2.1.5"
|
||||
esbuild "0.25.4"
|
||||
miniflare "4.20250816.0"
|
||||
path-to-regexp "6.3.0"
|
||||
unenv "2.0.0-rc.19"
|
||||
workerd "1.20250816.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
ws@8.18.0:
|
||||
version "8.18.0"
|
||||
resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz"
|
||||
integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
|
||||
|
||||
youch-core@^0.3.3:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz"
|
||||
integrity sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==
|
||||
dependencies:
|
||||
"@poppinss/exception" "^1.2.2"
|
||||
error-stack-parser-es "^1.0.5"
|
||||
|
||||
youch@4.1.0-beta.10:
|
||||
version "4.1.0-beta.10"
|
||||
resolved "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz"
|
||||
integrity sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==
|
||||
dependencies:
|
||||
"@poppinss/colors" "^4.1.5"
|
||||
"@poppinss/dumper" "^0.6.4"
|
||||
"@speed-highlight/core" "^1.2.7"
|
||||
cookie "^1.0.2"
|
||||
youch-core "^0.3.3"
|
||||
|
||||
zod@3.22.3:
|
||||
version "3.22.3"
|
||||
resolved "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz"
|
||||
integrity sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==
|
||||
+18
-10
@@ -42,7 +42,8 @@ func main() {
|
||||
|
||||
var viewers = make(map[string]Viewer)
|
||||
var mirrorActivity = make(map[int]int)
|
||||
var lock sync.Mutex
|
||||
var lockViewers sync.Mutex
|
||||
var lockMirrorActivity sync.Mutex
|
||||
|
||||
// Handle view counting
|
||||
http.HandleFunc("/viewcount", func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -60,18 +61,21 @@ func main() {
|
||||
}
|
||||
|
||||
// Update the last active time
|
||||
lock.Lock()
|
||||
lockViewers.Lock()
|
||||
viewers[ip] = Viewer{
|
||||
LastActive: now,
|
||||
ActiveMirror: metric.ActiveMirror,
|
||||
}
|
||||
var viewersCount = len(viewers)
|
||||
lockViewers.Unlock()
|
||||
|
||||
// Respond
|
||||
lockMirrorActivity.Lock()
|
||||
var response = ViewCountResponse{
|
||||
TotalCount: len(viewers),
|
||||
TotalCount: viewersCount,
|
||||
ByMirror: mirrorActivity,
|
||||
}
|
||||
lock.Unlock()
|
||||
lockMirrorActivity.Unlock()
|
||||
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@@ -88,13 +92,13 @@ func main() {
|
||||
var now = time.Now().Unix()
|
||||
|
||||
// Remove any viewers that have not been active in the last 10 seconds
|
||||
lock.Lock()
|
||||
lockViewers.Lock()
|
||||
for ip, viewer := range viewers {
|
||||
if now-viewer.LastActive > 10 {
|
||||
delete(viewers, ip)
|
||||
}
|
||||
}
|
||||
lock.Unlock()
|
||||
lockViewers.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -112,9 +116,9 @@ func main() {
|
||||
var last_count = 0
|
||||
for {
|
||||
var now = time.Now().Format(time.RFC3339)
|
||||
lock.Lock()
|
||||
lockViewers.Lock()
|
||||
var count = len(viewers)
|
||||
lock.Unlock()
|
||||
lockViewers.Unlock()
|
||||
|
||||
// If the viewer count has changed, log it
|
||||
if count != last_count {
|
||||
@@ -142,21 +146,23 @@ func main() {
|
||||
var counts = make(map[int]int)
|
||||
|
||||
// Loop through all viewers
|
||||
lock.Lock()
|
||||
lockViewers.Lock()
|
||||
for _, viewer := range viewers {
|
||||
// Increment the mirror count
|
||||
counts[viewer.ActiveMirror]++
|
||||
}
|
||||
lock.Unlock()
|
||||
lockViewers.Unlock()
|
||||
|
||||
// Check if the counts have changed
|
||||
var changed = false
|
||||
lockMirrorActivity.Lock()
|
||||
for mirror, count := range counts {
|
||||
if count != mirrorActivity[mirror] {
|
||||
changed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
lockMirrorActivity.Unlock()
|
||||
|
||||
// If the counts have changed, log them
|
||||
if changed {
|
||||
@@ -166,7 +172,9 @@ func main() {
|
||||
}
|
||||
|
||||
// Update the mirror activity
|
||||
lockMirrorActivity.Lock()
|
||||
mirrorActivity = counts
|
||||
lockMirrorActivity.Unlock()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -6,20 +6,33 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<link rel="stylesheet" href="./player.css" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/video.js@7.18.1/dist/video-js.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/videojs-hls-quality-selector@1.1.4/dist/videojs-hls-quality-selector.css"
|
||||
/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/video.js@7.18.1/dist/video.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/videojs-contrib-quality-levels@2.1.0/dist/videojs-contrib-quality-levels.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/videojs-hls-quality-selector@1.1.4/dist/videojs-hls-quality-selector.min.js"></script>
|
||||
<script src="./player.js"></script>
|
||||
<script id="config">
|
||||
window.restream_config = {
|
||||
upstreams: [
|
||||
{
|
||||
region: 'us-east',
|
||||
url: 'https://us.stream.holopirates.moe',
|
||||
region: 'de',
|
||||
url: 'https://concert.lytexx.dev',
|
||||
},
|
||||
{
|
||||
region: 'sg',
|
||||
url: 'https://restream.kitsune.box.ca',
|
||||
region: 'us',
|
||||
url: 'https://restream.dev',
|
||||
},
|
||||
{
|
||||
region: 'us',
|
||||
url: 'https://us.stream.holopirates.moe',
|
||||
},
|
||||
/*
|
||||
{
|
||||
region: 'eu',
|
||||
url: 'https://eu.stream.holopirates.moe',
|
||||
@@ -28,7 +41,10 @@
|
||||
region: 'jp',
|
||||
url: 'https://jp.stream.holopirates.moe',
|
||||
},
|
||||
*/
|
||||
{
|
||||
region: 'sg',
|
||||
url: 'https://restream.kitsune.box.ca',
|
||||
},
|
||||
],
|
||||
playlist: '/index.m3u8',
|
||||
};
|
||||
@@ -69,6 +85,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<video id="video" controls></video>
|
||||
<video-js
|
||||
controls
|
||||
autoplay
|
||||
preload="auto"
|
||||
id="video"
|
||||
class="vjs-default-skin vjs-big-play-centered"
|
||||
>
|
||||
</video-js>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
|
||||
body,
|
||||
html {
|
||||
min-height: 100%;
|
||||
height: 100vh;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
header {
|
||||
@@ -81,11 +83,11 @@ a:active {
|
||||
}
|
||||
|
||||
#video {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: black;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.loader {
|
||||
|
||||
+21
-22
@@ -79,7 +79,6 @@
|
||||
};
|
||||
|
||||
const reloadVideo = () => {
|
||||
const video = document.getElementById('video');
|
||||
const mirrorSelect = document.getElementById('mirror-select');
|
||||
const mirrorLink = document.getElementById('mirror-link');
|
||||
const playlistURL = mirrorSelect.value + window.restream_config.playlist;
|
||||
@@ -87,14 +86,25 @@
|
||||
if (window.restream_config.activeURL === playlistURL) return;
|
||||
|
||||
console.log('Reloading video from', playlistURL);
|
||||
if (Hls.isSupported()) {
|
||||
window.restream_config.hls.destroy();
|
||||
window.restream_config.hls = new Hls();
|
||||
window.restream_config.hls.attachMedia(video);
|
||||
window.restream_config.hls.loadSource(playlistURL);
|
||||
} else {
|
||||
video.src = playlistURL;
|
||||
if (typeof window.player === 'undefined') {
|
||||
window.player = videojs('video', {
|
||||
liveui: true,
|
||||
liveTracker: {
|
||||
liveTolerance: 5,
|
||||
},
|
||||
});
|
||||
window.player.volume(0.5);
|
||||
}
|
||||
window.player.src({
|
||||
src: playlistURL,
|
||||
type: 'application/x-mpegURL',
|
||||
});
|
||||
window.player.play();
|
||||
try {
|
||||
window.player.hlsQualitySelector({
|
||||
displayCurrentQuality: true,
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
window.restream_config.activeURL = playlistURL;
|
||||
mirrorLink.href = playlistURL;
|
||||
@@ -159,28 +169,17 @@
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
const video = document.getElementById('video');
|
||||
const mirrorSelect = document.getElementById('mirror-select');
|
||||
const mirrorPopup = document.getElementById('mirror-popup');
|
||||
const mirrorLoadProgress = document.getElementById('mirror-load-progress');
|
||||
const { upstreams } = window.restream_config;
|
||||
|
||||
// Set up hls.js
|
||||
if (Hls.isSupported()) {
|
||||
window.restream_config.hls = new Hls();
|
||||
window.restream_config.hls.attachMedia(video);
|
||||
}
|
||||
|
||||
// Set up event listeners
|
||||
mirrorSelect.addEventListener('change', () => reloadVideo());
|
||||
|
||||
// Measure latency
|
||||
let n = 0;
|
||||
for (const upstream of upstreams) {
|
||||
n += 1;
|
||||
await measureUpstreamLatency(upstream);
|
||||
mirrorLoadProgress.innerText = '(' + n + '/' + upstreams.length + ')';
|
||||
}
|
||||
await Promise.all(
|
||||
upstreams.map((upstream) => measureUpstreamLatency(upstream))
|
||||
);
|
||||
|
||||
// Choose the fastest upstream server
|
||||
const upstream = upstreams
|
||||
|
||||
Reference in New Issue
Block a user