From 760cc981299940ce815c8ae52a6d5f3816607d11 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 19 Oct 2024 10:31:44 -0600 Subject: [PATCH 01/10] Moving to hono --- README.md | 2 +- index.ts => index.tsx | 135 ++++--- package-lock.json | 853 ++++-------------------------------------- package.json | 8 +- tsconfig.json | 4 +- 5 files changed, 142 insertions(+), 860 deletions(-) rename index.ts => index.tsx (74%) diff --git a/README.md b/README.md index 6c377ba..829605a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

-Current version: **3.3.4** +Current version: **3.3.5** # About This takes ESPN/ESPN+, FOX Sports, Paramount+, MSG+, NFL+, B1G+, NESN, Mountain West, FloSports, CBS Sports, or MLB.tv programming and transforms it into a "live TV" experience with virtual linear channels. It will discover what is on, and generate a schedule of channels that will give you M3U and XMLTV files that you can import into something like [Jellyfin](https://jellyfin.org) or [Channels](https://getchannels.com). diff --git a/index.ts b/index.tsx similarity index 74% rename from index.ts rename to index.tsx index da6332b..d8f9990 100644 --- a/index.ts +++ b/index.tsx @@ -1,4 +1,6 @@ -import express from 'express'; +import {Context, Hono} from 'hono'; +import {serve} from '@hono/node-server'; +import {BlankEnv, BlankInput} from 'hono/types'; import moment from 'moment'; import {generateM3u} from './services/generate-m3u'; @@ -24,16 +26,26 @@ import {useLinear} from './services/channels'; import {version} from './package.json'; -const notFound = (_req, res) => { - res.writeHead(404, { +const notFound = (c: Context) => { + return c.text('404 not found', 404, { 'X-Tuner-Error': 'EPlusTV: Error getting content', }); - res.write('404 not found'); - res.end(); }; const shutDown = () => process.exit(0); +const getUri = (c: Context): string => { + if (process.env.BASE_URL) { + return process.env.BASE_URL; + } + + const protocol = c.req.header('x-forwarded-proto') || 'http'; + const host = c.req.header('host') || ''; + + + return `${protocol}://${host}`; +}; + const schedule = async () => { console.log('=== Getting events ==='); await espnHandler.getSchedule(); @@ -55,78 +67,66 @@ const schedule = async () => { console.log('=== Done building the schedule ==='); }; -const app = express(); +const app = new Hono(); -app.get('/channels.m3u', (req, res) => { - const uri = process.env.BASE_URL || `${req.protocol}://${req.headers.host}`; - const m3uFile = generateM3u(uri); +app.get('/channels.m3u', c => { + const m3uFile = generateM3u(getUri(c)); if (!m3uFile) { - notFound(req, res); - return; + return notFound(c); } - res.writeHead(200, { + return c.body(m3uFile, 200, { 'Content-Type': 'application/x-mpegurl', }); - res.end(m3uFile, 'utf-8'); }); -app.get('/linear-channels.m3u', (req, res) => { +app.get('/linear-channels.m3u', c => { if (!useLinear) { - notFound(req, res); - return; + return notFound(c); } - const uri = process.env.BASE_URL || `${req.protocol}://${req.headers.host}`; - const m3uFile = generateM3u(uri, true); + const m3uFile = generateM3u(getUri(c), true); if (!m3uFile) { - notFound(req, res); - return; + return notFound(c); } - res.writeHead(200, { + return c.body(m3uFile, 200, { 'Content-Type': 'application/x-mpegurl', }); - res.end(m3uFile, 'utf-8'); }); -app.get('/xmltv.xml', async (req, res) => { +app.get('/xmltv.xml', async c => { const xmlFile = await generateXml(); if (!xmlFile) { - notFound(req, res); - return; + return notFound(c); } - res.writeHead(200, { + return c.body(xmlFile, 200, { 'Content-Type': 'application/xml', }); - res.end(xmlFile, 'utf-8'); }); -app.get('/linear-xmltv.xml', async (req, res) => { +app.get('/linear-xmltv.xml', async c => { if (!useLinear) { - notFound(req, res); - return; + return notFound(c); } const xmlFile = await generateXml(true); if (!xmlFile) { - notFound(req, res); - return; + return notFound(c); } - res.writeHead(200, { + return c.body(xmlFile, 200, { 'Content-Type': 'application/xml', }); - res.end(xmlFile, 'utf-8'); }); -app.get('/channels/:id.m3u8', async (req, res) => { - const {id} = req.params; +app.get('/channels/:id{.+\\.m3u8$}', async c => { + const id = c.req.param('id').split('.m3u8')[0]; let contents: string | undefined; @@ -135,7 +135,7 @@ app.get('/channels/:id.m3u8', async (req, res) => { appStatus.channels[id] = {}; } - const uri = process.env.BASE_URL || `${req.protocol}://${req.headers.host}`; + const uri = getUri(c); if (!appStatus.channels[id].player?.playlist) { try { @@ -154,27 +154,25 @@ app.get('/channels/:id.m3u8', async (req, res) => { removeChannelStatus(id); - notFound(req, res); - return; + return notFound(c); } appStatus.channels[id].heartbeat = new Date(); - res.writeHead(200, { + return c.body(contents, 200, { 'Cache-Control': 'no-cache', 'Content-Type': 'application/vnd.apple.mpegurl', }); - res.end(contents, 'utf-8'); }); -app.get('/chunklist/:id/:chunklistid.m3u8', async (req, res) => { - const {id, chunklistid} = req.params; +app.get('/chunklist/:id/:chunklistid{.+\\.m3u8$}', async c => { + const id = c.req.param('id'); + const chunklistid = c.req.param('chunklistid').split('.m3u8')[0]; - let contents: string | null; + let contents: string | undefined; if (!appStatus.channels[id]?.player?.playlist) { - notFound(req, res); - return; + return notFound(c); } try { @@ -183,71 +181,65 @@ app.get('/chunklist/:id/:chunklistid.m3u8', async (req, res) => { if (!contents) { console.log(`Could not get chunklist for channel #${id}.`); - notFound(req, res); - return; + return notFound(c); } appStatus.channels[id].heartbeat = new Date(); - res.writeHead(200, { + return c.body(contents, 200, { 'Cache-Control': 'no-cache', 'Content-Type': 'application/vnd.apple.mpegurl', }); - res.end(contents, 'utf-8'); }); -app.get('/channels/:id/:part.key', async (req, res) => { - const {id, part} = req.params; +app.get('/channels/:id/:part{.+\\.key$}', async c => { + const id = c.req.param('id'); + const part = c.req.param('part').split('.key')[0]; let contents: ArrayBuffer | undefined; try { contents = await appStatus.channels[id].player?.getSegmentOrKey(part); } catch (e) { - notFound(req, res); - return; + return notFound(c); } if (!contents) { - notFound(req, res); - return; + return notFound(c); } appStatus.channels[id].heartbeat = new Date(); - res.writeHead(200, { + return c.body(contents, 200, { 'Cache-Control': 'no-cache', 'Content-Type': 'application/octet-stream', }); - res.end(contents, 'utf-8'); }); -app.get('/channels/:id/:part.ts', async (req, res) => { - const {id, part} = req.params; +app.get('/channels/:id/:part{.+\\.ts$}', async c => { + const id = c.req.param('id'); + const part = c.req.param('part').split('.ts')[0]; let contents: ArrayBuffer | undefined; try { contents = await appStatus.channels[id].player?.getSegmentOrKey(part); } catch (e) { - notFound(req, res); - return; + return notFound(c); } if (!contents) { - notFound(req, res); - return; + return notFound(c); } - res.writeHead(200, { + return c.body(contents, 200, { 'Cache-Control': 'no-cache', 'Content-Type': 'video/MP2T', }); - res.end(contents, 'utf-8'); }); // 404 Handler -app.use(notFound); +app.notFound(notFound); process.on('SIGTERM', shutDown); process.on('SIGINT', shutDown); @@ -288,8 +280,13 @@ process.on('SIGINT', shutDown); await schedule(); - console.log('=== Starting Server ==='); - app.listen(SERVER_PORT, () => console.log(`Server started on port ${SERVER_PORT}`)); + serve( + { + fetch: app.fetch, + port: SERVER_PORT, + }, + () => console.log(`Server started on port ${SERVER_PORT}`), + ); })(); // Check for events every 4 hours and set the schedule diff --git a/package-lock.json b/package-lock.json index e9e2593..03175b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,22 +1,23 @@ { "name": "eplustv", - "version": "3.3.4", + "version": "3.3.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "eplustv", - "version": "3.3.4", + "version": "3.3.5", "license": "MIT", "dependencies": { + "@hono/node-server": "^1.13.1", "axios": "^1.2.2", "axios-curlirize": "^1.3.7", "cheerio": "^1.0.0", "crypto-js": "^4.2.0", - "express": "^4.17.1", "fast-xml-parser": "^4.5.0", "fs-extra": "^10.0.0", "hls-parser": "^0.10.6", + "hono": "^4.6.3", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", "moment": "^2.29.1", @@ -39,6 +40,7 @@ "lint-staged": "^11.1.1", "prettier": "2.3.2", "ts-node": "^10.2.1", + "typed-htmx": "^0.3.1", "typescript": "^4.4.3" } }, @@ -218,6 +220,17 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@hono/node-server": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.13.1.tgz", + "integrity": "sha512-TSxE6cT5RHnawbjnveexVN7H2Dpn1YaLxQrCOLCUwD+hFbqbFsnJBgdWcYtASqtWVjA+Qgi8uqFug39GsHjo5A==", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -679,18 +692,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/acorn": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", @@ -825,11 +826,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -879,26 +875,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dependencies": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -940,14 +916,6 @@ "node": ">=6.14.2" } }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1100,38 +1068,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dependencies": { - "safe-buffer": "5.1.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -1199,14 +1135,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1221,19 +1149,6 @@ "node": ">=0.4.0" } }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -1318,25 +1233,12 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/encoding-sniffer": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", @@ -1392,11 +1294,6 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1702,14 +1599,6 @@ "node": ">=0.10.0" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -1733,46 +1622,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dependencies": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1861,23 +1710,6 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -1929,22 +1761,6 @@ "node": ">= 6" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/fs-extra": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", @@ -2074,6 +1890,14 @@ "resolved": "https://registry.npmjs.org/hls-parser/-/hls-parser-0.10.6.tgz", "integrity": "sha512-t9bKB1fDDVajh5CY/qeZanNMnCm4hAWMroDlflnuboOskYR26z29bEyOYwQRP1MxP2Y83UC2J93DQCC1AMhBCA==" }, + "node_modules/hono": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.6.3.tgz", + "integrity": "sha512-0LeEuBNFeSHGqZ9sNVVgZjB1V5fmhkBSB0hZrpqStSMLOWgfLy0dHOvrjbJh0H2khsjet6rbHfWTHY0kpYThKQ==", + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/htmlparser2": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", @@ -2092,21 +1916,6 @@ "entities": "^4.5.0" } }, - "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -2131,17 +1940,6 @@ "url": "https://github.com/sponsors/typicode" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ignore": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", @@ -2203,15 +2001,8 @@ "node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "node_modules/is-arrayish": { "version": "0.2.1", @@ -2565,19 +2356,6 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -2593,14 +2371,6 @@ "node": ">= 8" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -2614,17 +2384,6 @@ "node": ">=8.6" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/mime-db": { "version": "1.49.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", @@ -2684,11 +2443,6 @@ "node": "*" } }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2703,14 +2457,6 @@ "@seald-io/nedb": "^2.0.4" } }, - "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/node-gyp-build": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", @@ -2755,17 +2501,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2886,14 +2621,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2912,11 +2639,6 @@ "node": ">=8" } }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -2977,18 +2699,6 @@ "node": ">=0.4.0" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -3003,14 +2713,6 @@ "node": ">=6" } }, - "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3031,28 +2733,6 @@ } ] }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -3168,11 +2848,6 @@ "tslib": "^2.1.0" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -3199,53 +2874,6 @@ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", "dev": true }, - "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3307,14 +2935,6 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/string-argv": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", @@ -3481,14 +3101,6 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/ts-node": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", @@ -3584,16 +3196,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "node_modules/typed-html": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/typed-html/-/typed-html-3.0.1.tgz", + "integrity": "sha512-JKCM9zTfPDuPqQqdGZBWSEiItShliKkBFg5c6yOR8zth43v763XkAzTWaOlVqc0Y6p9ee8AaAbipGfUnCsYZUA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/typed-htmx": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/typed-htmx/-/typed-htmx-0.3.1.tgz", + "integrity": "sha512-6WSPsukTIOEMsVbx5wzgVSvldLmgBUVcFIm2vJlBpRPtcbDOGC5y1IYrCWNX1yUlNsrv1Ngcw4gGM8jsPyNV7w==", + "dev": true, "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "typed-html": "^3.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">=12" } }, "node_modules/typescript": { @@ -3625,14 +3246,6 @@ "node": ">= 10.0.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -3656,28 +3269,12 @@ "node": ">=6.14.2" } }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", @@ -3945,6 +3542,12 @@ } } }, + "@hono/node-server": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.13.1.tgz", + "integrity": "sha512-TSxE6cT5RHnawbjnveexVN7H2Dpn1YaLxQrCOLCUwD+hFbqbFsnJBgdWcYtASqtWVjA+Qgi8uqFug39GsHjo5A==", + "requires": {} + }, "@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -4289,15 +3892,6 @@ "eslint-visitor-keys": "^2.0.0" } }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, "acorn": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", @@ -4392,11 +3986,6 @@ "sprintf-js": "~1.0.2" } }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -4440,23 +4029,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - } - }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -4491,11 +4063,6 @@ "node-gyp-build": "^4.3.0" } }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -4609,29 +4176,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, "cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -4684,14 +4228,6 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4703,16 +4239,6 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -4770,22 +4296,12 @@ "domhandler": "^5.0.3" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, "encoding-sniffer": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", @@ -4828,11 +4344,6 @@ "is-arrayish": "^0.2.1" } }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -5057,11 +4568,6 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, "execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -5079,43 +4585,6 @@ "strip-final-newline": "^2.0.0" } }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5182,20 +4651,6 @@ "to-regex-range": "^5.0.1" } }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - } - }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -5227,16 +4682,6 @@ "mime-types": "^2.1.12" } }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, "fs-extra": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", @@ -5333,6 +4778,11 @@ "resolved": "https://registry.npmjs.org/hls-parser/-/hls-parser-0.10.6.tgz", "integrity": "sha512-t9bKB1fDDVajh5CY/qeZanNMnCm4hAWMroDlflnuboOskYR26z29bEyOYwQRP1MxP2Y83UC2J93DQCC1AMhBCA==" }, + "hono": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.6.3.tgz", + "integrity": "sha512-0LeEuBNFeSHGqZ9sNVVgZjB1V5fmhkBSB0hZrpqStSMLOWgfLy0dHOvrjbJh0H2khsjet6rbHfWTHY0kpYThKQ==" + }, "htmlparser2": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", @@ -5344,18 +4794,6 @@ "entities": "^4.5.0" } }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -5368,14 +4806,6 @@ "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", "dev": true }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, "ignore": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", @@ -5422,12 +4852,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "is-arrayish": { "version": "0.2.1", @@ -5706,16 +5132,6 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5728,11 +5144,6 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, "micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -5743,11 +5154,6 @@ "picomatch": "^2.3.1" } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, "mime-db": { "version": "1.49.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", @@ -5789,11 +5195,6 @@ "moment": "^2.29.4" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5808,11 +5209,6 @@ "@seald-io/nedb": "^2.0.4" } }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, "node-gyp-build": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", @@ -5843,14 +5239,6 @@ "boolbase": "^1.0.0" } }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5938,11 +5326,6 @@ "parse5": "^7.0.0" } }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -5955,11 +5338,6 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5999,15 +5377,6 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, "proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -6019,33 +5388,12 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -6119,11 +5467,6 @@ "tslib": "^2.1.0" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -6144,49 +5487,6 @@ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", "dev": true }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6236,11 +5536,6 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, "string-argv": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", @@ -6369,11 +5664,6 @@ "is-number": "^7.0.0" } }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, "ts-node": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", @@ -6432,13 +5722,19 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "typed-html": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/typed-html/-/typed-html-3.0.1.tgz", + "integrity": "sha512-JKCM9zTfPDuPqQqdGZBWSEiItShliKkBFg5c6yOR8zth43v763XkAzTWaOlVqc0Y6p9ee8AaAbipGfUnCsYZUA==", + "dev": true + }, + "typed-htmx": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/typed-htmx/-/typed-htmx-0.3.1.tgz", + "integrity": "sha512-6WSPsukTIOEMsVbx5wzgVSvldLmgBUVcFIm2vJlBpRPtcbDOGC5y1IYrCWNX1yUlNsrv1Ngcw4gGM8jsPyNV7w==", + "dev": true, "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "typed-html": "^3.0.1" } }, "typescript": { @@ -6457,11 +5753,6 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -6481,22 +5772,12 @@ "node-gyp-build": "^4.3.0" } }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, "whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", diff --git a/package.json b/package.json index 0eb012b..ca08f42 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,24 @@ { "name": "eplustv", - "version": "3.3.4", + "version": "3.3.5", "description": "", "scripts": { - "start": "ts-node index.ts", + "start": "ts-node index.tsx", "prepare": "husky install" }, "keywords": [], "author": "Joe Ipson ", "license": "MIT", "dependencies": { + "@hono/node-server": "^1.13.1", "axios": "^1.2.2", "axios-curlirize": "^1.3.7", "cheerio": "^1.0.0", "crypto-js": "^4.2.0", - "express": "^4.17.1", "fast-xml-parser": "^4.5.0", "fs-extra": "^10.0.0", "hls-parser": "^0.10.6", + "hono": "^4.6.3", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", "moment": "^2.29.1", @@ -40,6 +41,7 @@ "lint-staged": "^11.1.1", "prettier": "2.3.2", "ts-node": "^10.2.1", + "typed-htmx": "^0.3.1", "typescript": "^4.4.3" }, "lint-staged": { diff --git a/tsconfig.json b/tsconfig.json index 077fad3..16c23b0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,8 @@ { "compilerOptions": { "target": "es6", + "jsx": "react-jsx", + "jsxImportSource": "hono/jsx", "module": "commonjs", "rootDir": "./", "outDir": "./dist", @@ -12,4 +14,4 @@ "tmp", "slate" ] -} \ No newline at end of file +} From c11e8d60ae7935f2f42bea7d7fd0c24f5105a75d Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 20 Oct 2024 01:57:06 -0600 Subject: [PATCH 02/10] Most providers moved to UI --- README.md | 55 +---- favicon.ico | Bin 0 -> 15406 bytes index.tsx | 71 ++++++- package-lock.json | 102 +++++++++ package.json | 6 +- services/b1g-handler.ts | 102 +++++++-- services/build-schedule.ts | 4 + services/cbs-handler.ts | 116 +++++----- services/channels.ts | 61 ++++-- services/database.ts | 3 + services/flo-handler.ts | 126 ++++++----- services/fox-handler.ts | 199 +++++++++++------- services/generate-m3u.ts | 18 +- services/generate-xmltv.ts | 16 +- services/init-directories.ts | 13 +- services/mlb-handler.ts | 154 ++++++++------ services/mw-handler.ts | 28 ++- services/nesn-handler.ts | 165 +++++++++------ services/networks.ts | 1 + services/paramount-handler.ts | 176 ++++++++++------ services/providers/b1g/index.tsx | 63 ++++++ services/providers/b1g/views/CardBody.tsx | 34 +++ services/providers/b1g/views/Login.tsx | 57 +++++ services/providers/b1g/views/index.tsx | 42 ++++ services/providers/cbs-sports/index.tsx | 59 ++++++ .../providers/cbs-sports/views/CardBody.tsx | 34 +++ services/providers/cbs-sports/views/Login.tsx | 32 +++ services/providers/cbs-sports/views/index.tsx | 41 ++++ services/providers/flosports/index.tsx | 62 ++++++ .../providers/flosports/views/CardBody.tsx | 34 +++ services/providers/flosports/views/Login.tsx | 39 ++++ services/providers/flosports/views/index.tsx | 42 ++++ services/providers/fox/index.tsx | 104 +++++++++ services/providers/fox/views/CardBody.tsx | 58 +++++ services/providers/fox/views/Login.tsx | 35 +++ services/providers/fox/views/index.tsx | 77 +++++++ services/providers/index.ts | 21 ++ services/providers/mlb/index.tsx | 117 ++++++++++ services/providers/mlb/views/CardBody.tsx | 74 +++++++ services/providers/mlb/views/Login.tsx | 39 ++++ services/providers/mlb/views/index.tsx | 62 ++++++ services/providers/mw/index.tsx | 37 ++++ services/providers/mw/views/index.tsx | 36 ++++ services/providers/nesn/index.tsx | 61 ++++++ services/providers/nesn/views/CardBody.tsx | 58 +++++ services/providers/nesn/views/Login.tsx | 44 ++++ services/providers/nesn/views/index.tsx | 43 ++++ services/providers/paramount/index.tsx | 102 +++++++++ .../providers/paramount/views/CardBody.tsx | 73 +++++++ services/providers/paramount/views/Login.tsx | 36 ++++ services/providers/paramount/views/index.tsx | 43 ++++ services/shared-helpers.ts | 3 +- services/shared-interfaces.ts | 22 ++ tsconfig.json | 10 +- views/Header.tsx | 12 ++ views/Layout.tsx | 21 ++ views/Links.tsx | 75 +++++++ views/Main.tsx | 6 + views/Providers.tsx | 12 ++ views/Script.tsx | 21 ++ views/Style.tsx | 35 +++ 61 files changed, 2805 insertions(+), 487 deletions(-) create mode 100644 favicon.ico create mode 100644 services/providers/b1g/index.tsx create mode 100644 services/providers/b1g/views/CardBody.tsx create mode 100644 services/providers/b1g/views/Login.tsx create mode 100644 services/providers/b1g/views/index.tsx create mode 100644 services/providers/cbs-sports/index.tsx create mode 100644 services/providers/cbs-sports/views/CardBody.tsx create mode 100644 services/providers/cbs-sports/views/Login.tsx create mode 100644 services/providers/cbs-sports/views/index.tsx create mode 100644 services/providers/flosports/index.tsx create mode 100644 services/providers/flosports/views/CardBody.tsx create mode 100644 services/providers/flosports/views/Login.tsx create mode 100644 services/providers/flosports/views/index.tsx create mode 100644 services/providers/fox/index.tsx create mode 100644 services/providers/fox/views/CardBody.tsx create mode 100644 services/providers/fox/views/Login.tsx create mode 100644 services/providers/fox/views/index.tsx create mode 100644 services/providers/index.ts create mode 100644 services/providers/mlb/index.tsx create mode 100644 services/providers/mlb/views/CardBody.tsx create mode 100644 services/providers/mlb/views/Login.tsx create mode 100644 services/providers/mlb/views/index.tsx create mode 100644 services/providers/mw/index.tsx create mode 100644 services/providers/mw/views/index.tsx create mode 100644 services/providers/nesn/index.tsx create mode 100644 services/providers/nesn/views/CardBody.tsx create mode 100644 services/providers/nesn/views/Login.tsx create mode 100644 services/providers/nesn/views/index.tsx create mode 100644 services/providers/paramount/index.tsx create mode 100644 services/providers/paramount/views/CardBody.tsx create mode 100644 services/providers/paramount/views/Login.tsx create mode 100644 services/providers/paramount/views/index.tsx create mode 100644 views/Header.tsx create mode 100644 views/Layout.tsx create mode 100644 views/Links.tsx create mode 100644 views/Main.tsx create mode 100644 views/Providers.tsx create mode 100644 views/Script.tsx create mode 100644 views/Style.tsx diff --git a/README.md b/README.md index 829605a..bfa6d61 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

-Current version: **3.3.5** +Current version: **4.0.0** # About This takes ESPN/ESPN+, FOX Sports, Paramount+, MSG+, NFL+, B1G+, NESN, Mountain West, FloSports, CBS Sports, or MLB.tv programming and transforms it into a "live TV" experience with virtual linear channels. It will discover what is on, and generate a schedule of channels that will give you M3U and XMLTV files that you can import into something like [Jellyfin](https://jellyfin.org) or [Channels](https://getchannels.com). @@ -12,7 +12,7 @@ This takes ESPN/ESPN+, FOX Sports, Paramount+, MSG+, NFL+, B1G+, NESN, Mountain * The Mouse might not like it and it could be taken down at any minute. Enjoy it while it lasts. ¯\\_(ツ)_/¯ # Using -The server exposes 2 main endpoints: +The server exposes 4 main endpoints: | Endpoint | Description | |---|---| @@ -55,26 +55,13 @@ Use if you would like to login with a TV provider or ESPN+ and access various ES | ESPN_PPV | PPV: Set if you have purchased PPV events | False | #### FOX Sports -Use if you would like to login with a TV provider and access various FOX Sports events -| Environment Variable | Description | Required? | Default | -|---|---|---|---| -| FOXSPORTS** | Set if your TV provider supports it | No | False | -| MAX_RESOLUTION | Max resolution to use. Valid options are `UHD/HDR` and `720p` (Some events don't offer 4K and will attempt to play the highest framerate available for selected resolution). | No | 720p | -| FOX_ONLY_4K | Only grab 4K events | No | False | +Enable in your browser by going to the admin panel of the container #### Paramount+ -Use if you would like to login with Paramount+ -| Environment Variable | Description | Required? | Default | -|---|---|---|---| -| PARAMOUNTPLUS | Set if you would like CBS Sports events | False | False | -| CBSSPORTSHQ* | Set if you would like the CBS Sports HQ channel (only available with `LINEAR_CHANNELS`) | False | False | -| GOLAZO* | Set if you would like the Golazo Network channel (only available with `LINEAR_CHANNELS`) | False | False | +Enable in your browser by going to the admin panel of the container #### CBS Sports -Use if you would like to login with a TV provider and access various CBS Sports events -| Environment Variable | Description | Required? | Default | -|---|---|---|---| -| CBSSPORTS | Set if you would like CBS Sports events | False | False | +Enable in your browser by going to the admin panel of the container #### NFL+ Use if you would like to login with NFL+. @@ -94,20 +81,10 @@ Please note that if you only have an NFL account, you can still get events from | NFLCHANNEL* | Set if you would like the NFL Channel (only available with `LINEAR_CHANNELS`) | False | False | #### NESN -Use if you would like to login with NESN. Will get NESN and NESN+ programming - -4K events (home Red Sox and Bruins games will be scheduled normally) -| Environment Variable | Description | Default | -|---|---|---| -| NESN*** | Set if you would like to use NESN | False | +Enable in your browser by going to the admin panel of the container #### B1G+ -Use if you would like to login with your B1G+ account -| Environment Variable | Description | Default | -|---|---|---| -| B1GPLUS | Set if you would like to use B1G+ | False | -| B1GPLUS_USER | B1G+ Username | False | -| B1GPLUS_PASS | B1G+ Password | False | +Enable in your browser by going to the admin panel of the container #### MSG+ Use if you would like to login with your MSG+ account @@ -118,28 +95,16 @@ Use if you would like to login with your MSG+ account | MSGPLUS_PASS | MSG+ Password | False | #### FloSports -Use if you would like to login with FloSports -| Environment Variable | Description | Required? | Default | -|---|---|---|---| -| FLOSPORTS | Set if you would like FloSports events | False | False | +Enable in your browser by going to the admin panel of the container #### Mountain West -Use if you would like to use Mountain West -| Environment Variable | Description | Required? | Default | -|---|---|---|---| -| MTNWEST | Set if you would like Mountain West events | False | False | +Enable in your browser by going to the admin panel of the container #### MLB.tv -Use if you would like to login with your MLB.tv account +Enable in your browser by going to the admin panel of the container *** If `LINEAR_CHANNELS` is set, Big Inning will be on its own channel -| Environment Variable | Description | Default | -|---|---|---| -| MLBTV | Set if you would like to use MLB.tv | False | -| MLBTV_ONLY_FREE | Only schedule free games | False | - - ### Notes `*`: Dedicated linear channel - Will only schedule when `LINEAR_CHANNELS` is set diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a8f2239298b58617c38162a61fd3a0c1a6841445 GIT binary patch literal 15406 zcmeHNTZ~Re96#z>ij|O%RIEl+@PH;lRMM;v64!`C2=RatHjPBI2oG+p#O1*QSxL7% zATCX@?1LwlNF?gPB@$taM6CO5EsOnr{r_jq%$b>U&Uemt*|l1eOwP>z`kVjEobP<| zAJ1#$wf0I%JbIRTi`sbJaL@BfOJ#pRH_!W>XhVkh{QjPIzK7=xAQ@624N0d*WC0ps z7q@S7rF_OE%6<$vT3A{V-n2{CfZI1L`8r{VFom@Os&?iZ3pm=kPm17Z5pD>6CcBi$ zHQUNihT?zVzya*qwF@UsoDk%D_wM1Jni?g7ojZY>w`BLq6`=elik&fx&6|HCrX<|C za|e6&>=E{E-I7YvrvvBDOa1btK<}@C)2Fq0to-E{?f=oEM>uxun7~w9TPuW=enUee z`t<|;{1ceJFwkGMY85JWSKwszNkL@2yLayjMCIi`uU^2&k-)NLz}&e&Lj%yiKTuaM zZG51?eE9Hz#?&ZcYQ~AjNh~x{6;FTMOy|%`jQ~rirHuJ{ny=`Z;0kDlY>@w;Wb}GU z(9$YePB%154n$j2GimU-NqR2iC{wmpSb`}gHS(p91Cie|rBr{Q%I~MRV&h8anE(?+ zZFb&@wwadJb0@xu@inKrV)^>iXFdskQk;_X^^!>x%qEb8LVJmCDDy=y74PJ~&WQ_N z9KGelC;8-b z`=2^>s!0m9^YQ=sHPF2~@WmGr!(YcjW(6V6KYxF1-MSSUHf+GmnKLnQ;zZHr{%bbw zm$>mCIwburrSHqOZ5uIThSIQ~?7tU%5KfymO;`TjLJ*%{}%%ZrnKBzI|KQ7cX8|g0bj z=+XYCrD6Q+*|W4xx?}k8;kxeMzu%Am-oJm3ckkX=w8e{oHf_Rn!USN{DCv(r`9K8$uf3$gA`Ho`1Xa`6uPREO|0h_*ka1a-T#M_3(S|97g7z&M zF^aU9#E(>JN}}3bh52ZXVKs-3G*QUDcH&UR(bIU0kjY|B;&V_s-3W`tCB^xR#T};* z4=Z<#cv}T=)R@#Wjj^naXL(m{xmj-!XI zrk4!s8h;}qn4cJ_pg??LV^wfz%tae^l%W>$qE-Wrero6`@M_s;Q<9p(j#f`)P)irJ z5$8G*z7keXMiMEQD@4;^uDUtOC*e)vC%Q{vAmwmF|G~2C)D&JNav_*nI&rj3DG(W^ zW`Q2*ImJ+$1)Pr~UyLb+k+(<=<99{fK4FL;<%cX!L&*`2k?_glk=D|%G|p0MxUooMJO`Q7IC8LAm}tU)6WC$jNeW4Pwci>G-gkT^&1b`p=^$CvCw}`0 zB_jBo)G7omLuH-JbMN#S|rbU=?V$SM@ozP z9%N3O3G=z|#*G{&Q#R-XE#MhBC@U+&?Afz%^ypEmR##V3%qVD1VY@3nSvj8>oBow)zH`&Juax8bPPc9VpRp$ug@4_;bxER{&+*szRiHK3 zZq!oR%*Ag@$T^{_Md;Ki!0)w^IRkqRT+JZWQXb}koInx(F=cS^n>vht@7}!_Hf$IM z4<0Nk=SMnGzy=K(q-mRe-9+n{E-o1*4Su?gh2Fg-W?uV0|19%VyoM+hqxX_wRyWo9 z8AA!J_3PJLb<3756u(;WzBza99M-N~3%-ZNb;O7fv|jsS<;sX+?|q%Dl6gkX1#Q~IxgrfW)KK_`4jqbl^X6H#oDzk6N6anO`j2~|_)4|3 z2eYmJ2Fk(mzUDp4>xN$!_wNG)N66*OK$7cN*TR!8B_w*D;z>L~o2Bjr8omX|MqYuA9QR~spp z3d*HREZJFl94s(!AY;tn`|km|lBo;72AIb4!uKJa z^s$tq(DCon`0?Y>rArr)bLIDns{QE#2#WzXaO1kFR|H zfbUxN=pkk469BvyloK{vSt;|gZ0qph@H`7?66D-_eSLkX^7>Dcw`DtK;WbX?{F*V^ z0BtYPC)47afuAhPIo}`@602#4`N<`EjFw(F+!mWVDMUg#`4Lj!jWL|JrXHMb#CRwY zxyjr#nc*T0+?*k^T_p1#$&5RaG_#O#l|B;ou-i1~!&*h9Gzo;LfH#Sw+(HorD>n-T zNykROWSH%OyxG4aA9?8ckEEG^XAQf;kX0zf5L4-skn%?+m5M>K9mO&XWu>8vsXjlW zXeK}3c2n8S2~P?T+2WUzua+*HA{J?eP$V;^tI!k_!$-)d>9LsYVt{q=#Dg!`8=0o- NL7&U#2;?1se*yQ|nnwTt literal 0 HcmV?d00001 diff --git a/index.tsx b/index.tsx index d8f9990..e89facb 100644 --- a/index.tsx +++ b/index.tsx @@ -1,6 +1,8 @@ import {Context, Hono} from 'hono'; import {serve} from '@hono/node-server'; +import {serveStatic} from '@hono/node-server/serve-static'; import {BlankEnv, BlankInput} from 'hono/types'; +import {html} from 'hono/html'; import moment from 'moment'; import {generateM3u} from './services/generate-m3u'; @@ -23,9 +25,27 @@ import {cleanEntries, removeChannelStatus} from './services/shared-helpers'; import {appStatus} from './services/app-status'; import {SERVER_PORT} from './services/port'; import {useLinear} from './services/channels'; +import { providers } from './services/providers'; import {version} from './package.json'; +import { Layout } from './views/Layout'; +import { Header } from './views/Header'; +import { Main } from './views/Main'; +import { Links } from './views/Links'; +import { Style } from './views/Style'; +import { Providers } from './views/Providers'; +import { Script } from './views/Script'; + +import {CBSSports} from './services/providers/cbs-sports/views'; +import { MntWest } from './services/providers/mw/views'; +import {Paramount} from './services/providers/paramount/views'; +import {FloSports} from './services/providers/flosports/views'; +import {MlbTv} from './services/providers/mlb/views'; +import {FoxSports} from './services/providers/fox/views'; +import {Nesn} from './services/providers/nesn/views'; +import {B1G} from './services/providers/b1g/views'; + const notFound = (c: Context) => { return c.text('404 not found', 404, { 'X-Tuner-Error': 'EPlusTV: Error getting content', @@ -42,12 +62,12 @@ const getUri = (c: Context): string => { const protocol = c.req.header('x-forwarded-proto') || 'http'; const host = c.req.header('host') || ''; - return `${protocol}://${host}`; }; const schedule = async () => { console.log('=== Getting events ==='); + await espnHandler.getSchedule(); await foxHandler.getSchedule(); await mlbHandler.getSchedule(); @@ -61,16 +81,48 @@ const schedule = async () => { await cbsHandler.getSchedule(); console.log('=== Done getting events ==='); - await cleanEntries(); console.log('=== Building the schedule ==='); + + await cleanEntries(); await scheduleEntries(); + console.log('=== Done building the schedule ==='); }; const app = new Hono(); -app.get('/channels.m3u', c => { - const m3uFile = generateM3u(getUri(c)); +app.use('/node_modules/*', serveStatic({root: './'})); +app.use('/favicon.ico', serveStatic({root: './'})); + +app.route('/', providers); + +app.get('/', async c => { + return c.html( + html`${( + +
+
+ + + + + + + + + + + +
+ +); From d7d1f5cf0739bcc6ee5a48e32ac62b36bef120c4 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 20 Oct 2024 15:46:46 -0600 Subject: [PATCH 03/10] NFL moved to UI --- index.tsx | 2 + services/channels.ts | 11 +- services/nfl-handler.ts | 333 ++++++++++++++++++++++++------------ services/providers/index.ts | 2 + 4 files changed, 239 insertions(+), 109 deletions(-) diff --git a/index.tsx b/index.tsx index e89facb..5bda8f4 100644 --- a/index.tsx +++ b/index.tsx @@ -45,6 +45,7 @@ import {MlbTv} from './services/providers/mlb/views'; import {FoxSports} from './services/providers/fox/views'; import {Nesn} from './services/providers/nesn/views'; import {B1G} from './services/providers/b1g/views'; +import { NFL } from './services/providers/nfl/views'; const notFound = (c: Context) => { return c.text('404 not found', 404, { @@ -104,6 +105,7 @@ app.get('/', async c => {
+ diff --git a/services/channels.ts b/services/channels.ts index 966e76f..f99d863 100644 --- a/services/channels.ts +++ b/services/channels.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; -import {useAccN, useEspn1, useEspn2, useEspnews, useEspnU, useMsgPlus, useNfl, useSec} from './networks'; +import {useAccN, useEspn1, useEspn2, useEspnews, useEspnU, useMsgPlus, useSec} from './networks'; import {db} from './database'; import {IProvider} from './shared-interfaces'; @@ -156,7 +156,8 @@ export const CHANNELS = { tvgName: 'GOLAZO', }, 30: { - canUse: useNfl.network, + canUse: undefined, + checkChannelEnabled: () => checkChannelEnabled('nfl', 'NFLNETWORK'), id: 'NFLNETWORK', logo: 'https://tmsimg.fancybits.co/assets/s45399_ll_h15_aa.png?w=360&h=270', name: 'NFL Network', @@ -164,7 +165,8 @@ export const CHANNELS = { tvgName: 'NFLHD', }, 31: { - canUse: useNfl.redZone, + canUse: undefined, + checkChannelEnabled: () => checkChannelEnabled('nfl', 'NFLNRZ'), id: 'NFLNRZ', logo: 'https://tmsimg.fancybits.co/assets/s65025_ll_h9_aa.png?w=360&h=270', name: 'NFL RedZone', @@ -172,7 +174,8 @@ export const CHANNELS = { tvgName: 'NFLNRZD', }, 32: { - canUse: useNfl.channel, + canUse: undefined, + checkChannelEnabled: () => checkChannelEnabled('nfl', 'NFLDIGITAL1_OO_v3'), id: 'NFLDIGITAL1_OO_v3', logo: 'https://tmsimg.fancybits.co/assets/s121705_ll_h15_aa.png?w=360&h=270', name: 'NFL Channel', diff --git a/services/nfl-handler.ts b/services/nfl-handler.ts index 5476a55..0787d42 100644 --- a/services/nfl-handler.ts +++ b/services/nfl-handler.ts @@ -8,7 +8,7 @@ import jwt_decode from 'jwt-decode'; import {okHttpUserAgent} from './user-agent'; import {configPath} from './config'; import {useNfl} from './networks'; -import {IEntry, IHeaders} from './shared-interfaces'; +import {ClassTypeWithoutMethods, IEntry, IHeaders, IProvider} from './shared-interfaces'; import {db} from './database'; import {getRandomUUID} from './shared-helpers'; import {useLinear} from './channels'; @@ -157,7 +157,9 @@ const TV_DEVICE_INFO = { const DEFAULT_CATEGORIES = ['NFL', 'NFL+', 'Football']; -type TOtherAuth = 'prime' | 'tve' | 'peacock' | 'sunday_ticket'; +const nflConfigPath = path.join(configPath, 'nfl_tokens.json'); + +export type TOtherAuth = 'prime' | 'tve' | 'peacock' | 'sunday_ticket'; interface INFLJwt { dmaCode: string; @@ -243,41 +245,100 @@ class NflHandler { public youTubeUUID?: string; public initialize = async () => { - if (!useNfl.plus) { - return; - } + const setup = (await db.providers.count({name: 'nfl'})) > 0 ? true : false; + + if (!setup) { + const data: TNFLTokens = {}; + + if (useNfl.plus) { + this.loadJSON(); + + data.device_id = this.device_id; + data.access_token = this.access_token; + data.expires_at = this.expires_at; + data.refresh_token = this.refresh_token; + data.tv_access_token = this.tv_access_token; + data.tv_expires_at = this.tv_expires_at; + data.tv_refresh_token = this.tv_refresh_token; + data.uid = this.uid; + data.mvpdIdp = this.mvpdIdp; + data.mvpdUserId = this.mvpdUserId; + data.mvpdUUID = this.mvpdUUID; + data.amazonPrimeUUID = this.amazonPrimeUUID; + data.amazonPrimeUserId = this.amazonPrimeUserId; + data.peacockUserId = this.peacockUserId; + data.peacockUUID = this.peacockUUID; + data.youTubeUUID = this.youTubeUUID; + data.youTubeUserId = this.youTubeUserId; + } - // Load tokens from local file and make sure they are valid - this.load(); + await db.providers.insert>({ + enabled: useNfl.plus, + linear_channels: [ + { + enabled: useNfl.network, + id: 'NFLNETWORK', + name: 'NFL Network', + tmsId: '45399', + }, + { + enabled: useNfl.redZone, + id: 'NFLNRZ', + name: 'NFL RedZone', + tmsId: '65025', + }, + { + enabled: useNfl.channel, + id: 'NFLDIGITAL1_OO_v3', + name: 'NFL Channel', + tmsId: '121705', + }, + ], + name: 'nfl', + tokens: data, + }); - if (!this.device_id) { - this.device_id = getRandomUUID(); - this.save(); + if (fs.existsSync(nflConfigPath)) { + fs.rmSync(nflConfigPath); + } } - if (!this.expires_at || !this.access_token) { - await this.startProviderAuthFlow(); + if (useNfl.plus) { + console.log('Using NFLPLUS variable is no longer needed. Please use the UI going forward'); } - - if (useNfl.tve && (!this.mvpdIdp || !this.mvpdUserId || !this.mvpdUUID)) { - await this.startProviderAuthFlow('tve'); + if (useNfl.network) { + console.log('Using NFLNETWORK variable is no longer needed. Please use the UI going forward'); } - - if (useNfl.peacock && (!this.peacockUserId || !this.peacockUUID)) { - await this.startProviderAuthFlow('peacock'); + if (useNfl.channel) { + console.log('Using NFLCHANNEL variable is no longer needed. Please use the UI going forward'); } - - if (useNfl.prime && (!this.amazonPrimeUserId || !this.amazonPrimeUUID)) { - await this.startProviderAuthFlow('prime'); + if (useNfl.tve) { + console.log('Using NFL_TVE variable is no longer needed. Please use the UI going forward'); } + if (useNfl.peacock) { + console.log('Using NFL_PEACOCK variable is no longer needed. Please use the UI going forward'); + } + if (useNfl.prime) { + console.log('Using NFL_PRIME variable is no longer needed. Please use the UI going forward'); + } + if (useNfl.sundayTicket) { + console.log('Using NFL_SUNDAY_TICKET variable is no longer needed. Please use the UI going forward'); + } + + const {enabled} = await db.providers.findOne({name: 'nfl'}); - if (useNfl.sundayTicket && (!this.youTubeUserId || !this.youTubeUUID)) { - await this.startProviderAuthFlow('sunday_ticket'); + if (!enabled) { + return; } + + // Load tokens from local file and make sure they are valid + await this.load(); }; public refreshTokens = async () => { - if (!useNfl.plus) { + const {enabled} = await db.providers.findOne({name: 'nfl'}); + + if (!enabled) { return; } @@ -287,14 +348,17 @@ class NflHandler { }; public getSchedule = async (): Promise => { - if (!useNfl.plus) { + const {enabled} = await db.providers.findOne({name: 'nfl'}); + + if (!enabled) { return; } const {dmaCode}: INFLJwt = jwt_decode(this.access_token); - const redZoneAccess = this.checkRedZoneAccess(); - const nflNetworkAccess = this.checkNetworkAccess(); + const redZoneAccess = await this.checkRedZoneAccess(); + const nflNetworkAccess = await this.checkNetworkAccess(); + const nflChannelAccess = await this.checkChannelAccess(); const hasPlus = this.checkPlusAccess(); if (!dmaCode) { @@ -302,7 +366,7 @@ class NflHandler { return; } - console.log('Looking for NFL+ events...'); + console.log('Looking for NFL events...'); const events: INFLEvent[] = []; try { @@ -357,7 +421,7 @@ class NflHandler { } }); - if (useNfl.channel && useLinear) { + if (nflChannelAccess && useLinear) { const url = [ 'https://', 'api.nfl.com', @@ -380,7 +444,7 @@ class NflHandler { await parseAirings(events); } catch (e) { console.error(e); - console.log('Could not parse NFL+ events'); + console.log('Could not parse NFL events'); } }; @@ -421,32 +485,67 @@ class NflHandler { } }; - private checkRedZoneAccess = (): boolean => { + private updateChannelAccess = async (index: number, enabled: boolean): Promise => { + const {linear_channels} = await db.providers.findOne>({name: 'nfl'}); + + const updatedChannels = linear_channels.map((c, i) => { + if (i !== index) { + return c; + } + + c.enabled = enabled; + return c; + }); + + await db.providers.update({name: 'nfl'}, {$set: {linear_channels: updatedChannels}}); + }; + + private checkRedZoneAccess = async (): Promise => { try { const {plans, networks}: INFLJwt = jwt_decode(this.access_token); if (plans) { - useNfl.redZone = + const redZoneAccess = plans.findIndex(p => p.plan === 'NFL_PLUS_PREMIUM' && p.status === 'ACTIVE') > -1 || networks?.NFLRZ ? true : false; + + await this.updateChannelAccess(1, redZoneAccess); + + return redZoneAccess; } - } catch (e) {} + } catch (e) { + await this.updateChannelAccess(1, false); + } - return useNfl.redZone; + return false; }; - private checkNetworkAccess = (): boolean => { + private checkNetworkAccess = async (): Promise => { try { const {plans, networks}: INFLJwt = jwt_decode(this.tv_access_token); if (plans) { - const hasPlus = (this.checkPlusAccess() || networks?.NFLN) && useLinear ? true : false; - useNfl.network = hasPlus; + const networkAccess = (this.checkPlusAccess() || networks?.NFLN) && useLinear ? true : false; + await this.updateChannelAccess(0, networkAccess); + + return networkAccess; } + } catch (e) { + await this.updateChannelAccess(0, false); + } + + return false; + }; + + private checkChannelAccess = async (): Promise => { + try { + const {linear_channels} = await db.providers.findOne>({name: 'nfl'}); + + return linear_channels[2].enabled; } catch (e) {} - return useNfl.network; + return false; }; private checkPlusAccess = (): boolean => { @@ -466,10 +565,10 @@ class NflHandler { return hasPlus; }; - private checkTVEAccess = (): boolean => (this.mvpdIdp && useNfl.tve ? true : false); - private checkPeacockAccess = (): boolean => (this.peacockUserId && useNfl.peacock ? true : false); - private checkPrimeAccess = (): boolean => (this.amazonPrimeUserId && useNfl.prime ? true : false); - private checkSundayTicket = (): boolean => (this.youTubeUserId && useNfl.sundayTicket ? true : false); + private checkTVEAccess = (): boolean => (this.mvpdIdp ? true : false); + private checkPeacockAccess = (): boolean => (this.peacockUserId ? true : false); + private checkPrimeAccess = (): boolean => (this.amazonPrimeUserId ? true : false); + private checkSundayTicket = (): boolean => (this.youTubeUserId ? true : false); private checkTVEEventAccess = (event: INFLEvent): boolean => { let hasChannel = false; @@ -549,13 +648,13 @@ class NflHandler { }); } - this.save(); + await this.save(); - this.checkRedZoneAccess(); - this.checkNetworkAccess(); + await this.checkRedZoneAccess(); + await this.checkNetworkAccess(); } catch (e) { console.error(e); - console.log('Could not refresh token for NFL+'); + console.log('Could not refresh token for NFL'); } }; @@ -616,13 +715,13 @@ class NflHandler { }); } - this.save(); + await this.save(); - this.checkRedZoneAccess(); - this.checkNetworkAccess(); + await this.checkRedZoneAccess(); + await this.checkNetworkAccess(); } catch (e) { console.error(e); - console.log('Could not refresh token for NFL+'); + console.log('Could not refresh token for NFL'); } }; @@ -656,11 +755,11 @@ class NflHandler { if (this.uid) { this.expires_at = data.expiresIn; - this.save(); + await this.save(); } } catch (e) { console.error(e); - console.log('Could not get token for NFL+'); + console.log('Could not get token for NFL'); } }; @@ -689,15 +788,36 @@ class NflHandler { if (this.uid) { this.tv_expires_at = data.expiresIn; - this.save(); + await this.save(); } } catch (e) { console.error(e); - console.log('Could not get TV token for NFL+'); + console.log('Could not get TV token for NFL'); } }; - private startProviderAuthFlow = async (otherAuth?: TOtherAuth): Promise => { + public getAuthCode = async (otherAuth?: TOtherAuth): Promise<[string, string?]> => { + // Reset state + if (!otherAuth) { + this.device_id = getRandomUUID(); + this.access_token = undefined; + this.expires_at = undefined; + this.refresh_token = undefined; + this.tv_access_token = undefined; + this.tv_expires_at = undefined; + this.tv_refresh_token = undefined; + this.uid = undefined; + this.mvpdIdp = undefined; + this.mvpdUserId = undefined; + this.mvpdUUID = undefined; + this.amazonPrimeUUID = undefined; + this.amazonPrimeUserId = undefined; + this.peacockUserId = undefined; + this.peacockUUID = undefined; + this.youTubeUUID = undefined; + this.youTubeUserId = undefined; + } + try { await this.getTokens(); @@ -752,56 +872,14 @@ class NflHandler { }, ); - const otherAuthName = - otherAuth === 'tve' - ? '(TV Provider) ' - : otherAuth === 'prime' - ? '(Amazon Prime) ' - : otherAuth === 'peacock' - ? '(Peacock) ' - : otherAuth === 'sunday_ticket' - ? '(Youtube) ' - : ''; - - console.log(`=== NFL+ Auth ${otherAuthName}===`); - console.log(`Please open a browser window and go to: https://id.nfl.com/account/activate?regCode=${code}`); - console.log('Enter code: ', code); - console.log('App will continue when login has completed...'); - - return new Promise(async (resolve, reject) => { - // Reg code expires in 5 minutes - const maxNumOfReqs = 30; - - let numOfReqs = 0; - - const authenticate = async () => { - if (numOfReqs < maxNumOfReqs) { - const res = await this.authenticateRegCode(code, otherAuth); - numOfReqs += 1; - - if (res) { - clearInterval(regInterval); - resolve(); - } - } else { - clearInterval(regInterval); - reject(); - } - }; - - const regInterval = setInterval(() => { - authenticate(); - }, 10 * 1000); - - await authenticate(); - }); + return [code, otherAuth]; } catch (e) { console.error(e); console.log('Could not start the authentication process for Fox Sports!'); } }; - private authenticateRegCode = async (code: string, otherAuth?: TOtherAuth): Promise => { + public authenticateRegCode = async (code: string, otherAuth?: TOtherAuth): Promise => { try { const url = ['https://', 'api.nfl.com', '/keystore/v1/mvpd/', code].join(''); @@ -836,7 +914,7 @@ class NflHandler { this.youTubeUUID = data.uuid; } - this.save(); + await this.save(); await this.extendToken(); await this.extendTvToken(); @@ -857,12 +935,55 @@ class NflHandler { } }; - private save = () => { - fsExtra.writeJSONSync(path.join(configPath, 'nfl_tokens.json'), this, {spaces: 2}); + private save = async (): Promise => { + await db.providers.update({name: 'nfl'}, {$set: {tokens: this}}); }; - private load = () => { - if (fs.existsSync(path.join(configPath, 'nfl_tokens.json'))) { + private load = async (): Promise => { + const {tokens} = await db.providers.findOne>({name: 'nfl'}); + const { + device_id, + access_token, + expires_at, + refresh_token, + uid, + tv_access_token, + tv_expires_at, + tv_refresh_token, + mvpdIdp, + mvpdUserId, + mvpdUUID, + amazonPrimeUserId, + amazonPrimeUUID, + peacockUserId, + peacockUUID, + youTubeUserId, + youTubeUUID, + } = tokens; + + this.device_id = device_id; + this.access_token = access_token; + this.expires_at = expires_at; + this.refresh_token = refresh_token; + this.tv_access_token = tv_access_token; + this.tv_expires_at = tv_expires_at; + this.tv_refresh_token = tv_refresh_token; + this.uid = uid; + + // Supplemental Auth + this.mvpdIdp = mvpdIdp; + this.mvpdUserId = mvpdUserId; + this.mvpdUUID = mvpdUUID; + this.amazonPrimeUUID = amazonPrimeUUID; + this.amazonPrimeUserId = amazonPrimeUserId; + this.peacockUserId = peacockUserId; + this.peacockUUID = peacockUUID; + this.youTubeUUID = youTubeUUID; + this.youTubeUserId = youTubeUserId; + }; + + private loadJSON = () => { + if (fs.existsSync(nflConfigPath)) { const { device_id, access_token, @@ -881,7 +1002,7 @@ class NflHandler { peacockUUID, youTubeUserId, youTubeUUID, - } = fsExtra.readJSONSync(path.join(configPath, 'nfl_tokens.json')); + } = fsExtra.readJSONSync(nflConfigPath); this.device_id = device_id; this.access_token = access_token; @@ -906,4 +1027,6 @@ class NflHandler { }; } +export type TNFLTokens = ClassTypeWithoutMethods; + export const nflHandler = new NflHandler(); diff --git a/services/providers/index.ts b/services/providers/index.ts index 46206ce..625aac3 100644 --- a/services/providers/index.ts +++ b/services/providers/index.ts @@ -8,6 +8,7 @@ import {mlbtv} from './mlb'; import {fox} from './fox'; import {nesn} from './nesn'; import {b1g} from './b1g'; +import {nfl} from './nfl'; export const providers = new Hono().basePath('/providers'); @@ -19,3 +20,4 @@ providers.route('/', mlbtv); providers.route('/', fox); providers.route('/', nesn); providers.route('/', b1g); +providers.route('/', nfl); From 12eb23041155ca28eee172050ccbead564f3b6ca Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 20 Oct 2024 15:46:52 -0600 Subject: [PATCH 04/10] NFL moved to UI --- services/providers/nfl/index.tsx | 146 ++++++++++++++++++++++ services/providers/nfl/views/CardBody.tsx | 142 +++++++++++++++++++++ services/providers/nfl/views/Login.tsx | 50 ++++++++ services/providers/nfl/views/index.tsx | 43 +++++++ 4 files changed, 381 insertions(+) create mode 100644 services/providers/nfl/index.tsx create mode 100644 services/providers/nfl/views/CardBody.tsx create mode 100644 services/providers/nfl/views/Login.tsx create mode 100644 services/providers/nfl/views/index.tsx diff --git a/services/providers/nfl/index.tsx b/services/providers/nfl/index.tsx new file mode 100644 index 0000000..aab5be8 --- /dev/null +++ b/services/providers/nfl/index.tsx @@ -0,0 +1,146 @@ +import {Hono} from 'hono'; + +import { db } from '@/services/database'; + +import { Login } from './views/Login'; +import { IProvider } from '@/services/shared-interfaces'; +import { removeEntriesProvider, scheduleEntries } from '@/services/build-schedule'; +import { nflHandler, TNFLTokens, TOtherAuth } from '@/services/nfl-handler'; +import { NFLBody } from './views/CardBody'; + +export const nfl = new Hono().basePath('/nfl'); + +const scheduleEvents = async () => { + await nflHandler.getSchedule(); + await scheduleEntries(); +}; + +const removeEvents = async () => { + await removeEntriesProvider('nfl+'); +}; + +nfl.put('/toggle', async c => { + const body = await c.req.parseBody(); + const enabled = body['nfl-enabled'] === 'on'; + + if (!enabled) { + await db.providers.update({name: 'nfl'}, {$set: {enabled, tokens: {}}}); + removeEvents(); + + return c.html(<>); + } + + return c.html(); +}); + +nfl.put('/auth/:provider', async c => { + const provider = c.req.param('provider') as TOtherAuth; + const body = await c.req.parseBody(); + const enabled = body[`nfl-${provider}-enabled`] === 'on'; + + const {tokens} = await db.providers.findOne>({name: 'nfl'}); + + const updatedTokens = {...tokens}; + + if (!enabled) { + switch (provider) { + case 'peacock': + delete updatedTokens.peacockUUID; + delete updatedTokens.peacockUserId; + break; + case 'prime': + delete updatedTokens.amazonPrimeUUID; + delete updatedTokens.amazonPrimeUserId; + break; + case 'tve': + delete updatedTokens.mvpdIdp; + delete updatedTokens.mvpdUUID; + delete updatedTokens.mvpdUserId; + break; + case 'sunday_ticket': + delete updatedTokens.youTubeUUID; + delete updatedTokens.youTubeUserId; + break; + } + + const {linear_channels, tokens} = await db.providers.update>({name: 'nfl'}, {$set: {tokens: updatedTokens}}, {returnUpdatedDocs: true}); + + return c.html(); + } + + return c.html(); +}); + +nfl.get('/login/:code/:other', async c => { + const code = c.req.param('code'); + const otherAuth = c.req.param('other'); + + const provider = otherAuth === 'undefined' ? undefined : (otherAuth as TOtherAuth); + + const isAuthenticated = await nflHandler.authenticateRegCode(code, provider); + + if (!isAuthenticated) { + return c.html(); + } + + const {tokens, linear_channels} = await db.providers.update>( + {name: 'nfl'}, + {$set: {enabled: true}}, + {returnUpdatedDocs: true}, + ); + + // Kickoff event scheduler + scheduleEvents(); + + return c.html(, 200, { + 'HX-Trigger': `{"HXToast":{"type":"success","body":"Successfully enabled NFL"}}`, + }); +}); + +nfl.put('/reauth', async c => { + return c.html(); +}); + +nfl.put('/channels/toggle/:id', async c => { + const channelId = c.req.param('id'); + const {linear_channels} = await db.providers.findOne({name: 'nfl'}); + + const body = await c.req.parseBody(); + const enabled = body['channel-enabled'] === 'on'; + + let updatedChannel = channelId; + + const updatedChannels = linear_channels.map(channel => { + if (channel.id === channelId) { + updatedChannel = channel.name; + return {...channel, enabled: !channel.enabled}; + } + return channel; + }); + + if (updatedChannel !== channelId) { + await db.providers.update({name: 'nfl'}, {$set: {linear_channels: updatedChannels}}); + + // Kickoff event scheduler + scheduleEvents(); + + return c.html( + , + 200, + { + ...(enabled && { + 'HX-Trigger': `{"HXToast":{"type":"success","body":"Successfully enabled ${updatedChannel}"}}`, + }) + }, + ); + } +}); diff --git a/services/providers/nfl/views/CardBody.tsx b/services/providers/nfl/views/CardBody.tsx new file mode 100644 index 0000000..4c7176c --- /dev/null +++ b/services/providers/nfl/views/CardBody.tsx @@ -0,0 +1,142 @@ +import {FC} from 'hono/jsx'; + +import { TNFLTokens } from '@/services/nfl-handler'; +import { IProviderChannel } from '@/services/shared-interfaces'; +import { useLinear } from '@/services/channels'; + +interface INFLBodyProps { + enabled: boolean; + tokens?: TNFLTokens; + open?: boolean; + channels: IProviderChannel[]; +} + +export const NFLBody: FC = ({enabled, tokens, open, channels}) => { + const parsedTokens = JSON.stringify(tokens, undefined, 2); + + if (!enabled) { + return null; + } + + return ( +
+ + + Linear Channels + + + + + + + + + + + {channels.map(c => ( + + + + + ))} + +
Name
+ + {c.name}
+
+
TV Provider:
+
+ +
+
+
+
Peacock:
+
+ +
+
+
+
Amazon Prime:
+
+ +
+
+
+
Sunday Ticket:
+
+ +
+
+
+ Tokens +
+
{parsedTokens}
+
+ +
+
+
+
+ ); +}; diff --git a/services/providers/nfl/views/Login.tsx b/services/providers/nfl/views/Login.tsx new file mode 100644 index 0000000..5e90573 --- /dev/null +++ b/services/providers/nfl/views/Login.tsx @@ -0,0 +1,50 @@ +import {FC} from 'hono/jsx'; + +import { nflHandler, TOtherAuth } from '@/services/nfl-handler'; + +interface ILogin { + code?: string; + otherAuth?: TOtherAuth; +} + +export const Login: FC = async ({code, otherAuth}) => { + let shownCode = code; + + if (!shownCode) { + [shownCode] = await nflHandler.getAuthCode(otherAuth); + } + + const otherAuthName = + otherAuth === 'tve' + ? ' (TV Provider)' + : otherAuth === 'prime' + ? ' (Amazon Prime)' + : otherAuth === 'peacock' + ? ' (Peacock)' + : otherAuth === 'sunday_ticket' + ? ' (Youtube)' + : ''; + + return ( +
+
+
+
{`NFL Login${otherAuthName}`}:
+ + Open this link and follow instructions: +
+ + {`https://id.nfl.com/account/activate?regCode=${shownCode}`} + +
+
+
+
+
+ ); +}; diff --git a/services/providers/nfl/views/index.tsx b/services/providers/nfl/views/index.tsx new file mode 100644 index 0000000..c374afd --- /dev/null +++ b/services/providers/nfl/views/index.tsx @@ -0,0 +1,43 @@ +import {FC} from 'hono/jsx'; + +import { db } from '@/services/database'; +import { IProvider } from '@/services/shared-interfaces'; +import { TNFLTokens } from '@/services/nfl-handler'; + +import { NFLBody } from './CardBody'; + +export const NFL: FC = async () => { + const nfl = await db.providers.findOne>({name: 'nfl'}); + const enabled = nfl?.enabled; + const tokens = nfl?.tokens; + const channels = nfl?.linear_channels || []; + + return ( +
+
+
+

NFL

+
+ +
+
+
+ +
+
+
+
+ ); +}; From 48c884afc587f66285ae931e741ba23cf61ec5b8 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 20 Oct 2024 15:56:49 -0600 Subject: [PATCH 05/10] NFL moved to UI --- services/providers/nfl/index.tsx | 15 ++++++++++++++- services/providers/nfl/views/CardBody.tsx | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/services/providers/nfl/index.tsx b/services/providers/nfl/index.tsx index aab5be8..1df2400 100644 --- a/services/providers/nfl/index.tsx +++ b/services/providers/nfl/index.tsx @@ -92,8 +92,21 @@ nfl.get('/login/:code/:other', async c => { // Kickoff event scheduler scheduleEvents(); + const otherAuthName = + otherAuth === 'tve' + ? ' (TV Provider)' + : otherAuth === 'prime' + ? ' (Amazon Prime)' + : otherAuth === 'peacock' + ? ' (Peacock)' + : otherAuth === 'sunday_ticket' + ? ' (Youtube)' + : ''; + + const message = `NFL${otherAuthName}`; + return c.html(, 200, { - 'HX-Trigger': `{"HXToast":{"type":"success","body":"Successfully enabled NFL"}}`, + 'HX-Trigger': `{"HXToast":{"type":"success","body":"Successfully enabled ${message}"}}`, }); }); diff --git a/services/providers/nfl/views/CardBody.tsx b/services/providers/nfl/views/CardBody.tsx index 4c7176c..83e1c40 100644 --- a/services/providers/nfl/views/CardBody.tsx +++ b/services/providers/nfl/views/CardBody.tsx @@ -45,7 +45,7 @@ export const NFLBody: FC = ({enabled, tokens, open, channels}) => type="checkbox" checked={c.enabled} data-enabled={c.enabled ? 'true' : 'false'} - disabled={!useLinear} + disabled={!useLinear || c.id === 'NFLNRZ'} hx-put={`/providers/nfl/channels/toggle/${c.id}`} hx-trigger="change" name="channel-enabled" From a77aa27ff4426d991ff9a5fb1358fc842a024337 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 20 Oct 2024 16:53:04 -0600 Subject: [PATCH 06/10] Some general cleanup --- index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/index.tsx b/index.tsx index 5bda8f4..1f8055f 100644 --- a/index.tsx +++ b/index.tsx @@ -235,6 +235,7 @@ app.get('/chunklist/:id/:chunklistid{.+\\.m3u8$}', async c => { if (!contents) { console.log(`Could not get chunklist for channel #${id}.`); + removeChannelStatus(id); return notFound(c); } From ba08397a37193a40f253241dd4f555ced70ffb5f Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 21 Oct 2024 00:33:54 -0600 Subject: [PATCH 07/10] ESPN mostly done --- index.tsx | 23 +- services/channels.ts | 20 +- services/espn-handler.ts | 551 +++++++++++------- services/providers/espn-plus/index.tsx | 70 +++ .../providers/espn-plus/views/CardBody.tsx | 34 ++ services/providers/espn-plus/views/Login.tsx | 26 + services/providers/espn-plus/views/index.tsx | 60 ++ services/providers/espn/index.tsx | 142 +++++ services/providers/espn/views/CardBody.tsx | 131 +++++ services/providers/espn/views/Login.tsx | 39 ++ services/providers/espn/views/index.tsx | 40 ++ services/providers/index.ts | 4 + services/shared-helpers.ts | 4 + views/Tools.tsx | 38 ++ 14 files changed, 976 insertions(+), 206 deletions(-) create mode 100644 services/providers/espn-plus/index.tsx create mode 100644 services/providers/espn-plus/views/CardBody.tsx create mode 100644 services/providers/espn-plus/views/Login.tsx create mode 100644 services/providers/espn-plus/views/index.tsx create mode 100644 services/providers/espn/index.tsx create mode 100644 services/providers/espn/views/CardBody.tsx create mode 100644 services/providers/espn/views/Login.tsx create mode 100644 services/providers/espn/views/index.tsx create mode 100644 views/Tools.tsx diff --git a/index.tsx b/index.tsx index 1f8055f..072d8b6 100644 --- a/index.tsx +++ b/index.tsx @@ -21,7 +21,7 @@ import {msgHandler} from './services/msg-handler'; import {mwHandler} from './services/mw-handler'; import {nesnHandler} from './services/nesn-handler'; import {cbsHandler} from './services/cbs-handler'; -import {cleanEntries, removeChannelStatus} from './services/shared-helpers'; +import {cleanEntries, removeAllEntries, removeChannelStatus} from './services/shared-helpers'; import {appStatus} from './services/app-status'; import {SERVER_PORT} from './services/port'; import {useLinear} from './services/channels'; @@ -36,6 +36,7 @@ import { Links } from './views/Links'; import { Style } from './views/Style'; import { Providers } from './views/Providers'; import { Script } from './views/Script'; +import {Tools} from './views/Tools'; import {CBSSports} from './services/providers/cbs-sports/views'; import { MntWest } from './services/providers/mw/views'; @@ -45,7 +46,9 @@ import {MlbTv} from './services/providers/mlb/views'; import {FoxSports} from './services/providers/fox/views'; import {Nesn} from './services/providers/nesn/views'; import {B1G} from './services/providers/b1g/views'; -import { NFL } from './services/providers/nfl/views'; +import {NFL} from './services/providers/nfl/views'; +import {ESPN} from './services/providers/espn/views'; +import {ESPNPlus} from './services/providers/espn-plus/views'; const notFound = (c: Context) => { return c.text('404 not found', 404, { @@ -104,16 +107,19 @@ app.get('/', async c => {
+ + - + + - +