diff --git a/.vscode/settings.json b/.vscode/settings.json
index d7b6bb4..845380d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,13 +1,10 @@
{
- "typescript.tsdk": "node_modules/typescript/lib",
- "typescript.enablePromptUseWorkspaceTsdk": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "always"
},
"editor.formatOnSave": true,
- "extensions.ignoreRecommendations": false,
- "eslint.useESLintClass": true,
- "eslint.useFlatConfig": true,
+ "editor.linkedEditing": true,
+ "editor.tabSize": 2,
"eslint.format.enable": true,
"eslint.probe": [
"javascript",
@@ -17,6 +14,8 @@
"svelte",
"html"
],
+ "eslint.useESLintClass": true,
+ "eslint.useFlatConfig": true,
"eslint.validate": [
"javascript",
"javascriptreact",
@@ -24,5 +23,21 @@
"typescriptreact",
"svelte",
"html"
- ]
+ ],
+ "javascript.preferences.importModuleSpecifierEnding": "minimal",
+ "javascript.preferences.quoteStyle": "single",
+ "javascript.suggest.autoImports": true,
+ "javascript.updateImportsOnFileMove.enabled": "always",
+ "javascript.validate.enable": true,
+ "extensions.ignoreRecommendations": false,
+ "svelte.plugin.svelte.format.config.singleQuote": true,
+ "svelte.plugin.svelte.format.enable": false,
+ "typescript.enablePromptUseWorkspaceTsdk": true,
+ "typescript.experimental.expandableHover": true,
+ "typescript.preferences.importModuleSpecifierEnding": "minimal",
+ "typescript.preferences.quoteStyle": "single",
+ "typescript.suggest.autoImports": true,
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "typescript.updateImportsOnFileMove.enabled": "always",
+ "typescript.validate.enable": true
}
\ No newline at end of file
diff --git a/package.json b/package.json
index 47e1cf2..7ee714a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ui",
- "version": "6.3.16",
+ "version": "6.3.17",
"license": "BUSL-1.1",
"private": true,
"packageManager": "pnpm@9.14.4",
@@ -36,6 +36,7 @@
"svelte-radix": "^1.1.1",
"svelte-sonner": "^0.3.28",
"tailwindcss": "^3.4.17",
+ "typescript": "^5.8.3",
"vaul-svelte": "^0.3.2",
"vite": "^5.4.11"
},
@@ -63,7 +64,7 @@
"js-levenshtein": "^1.1.6",
"lucide-svelte": "^0.511.0",
"marked": "^15.0.11",
- "p2pt": "^1.5.1",
+ "p2pt": "github:ThaUnknown/p2pt#modernise",
"rollup-plugin-license": "^3.6.0",
"semver": "^7.7.2",
"simple-store-svelte": "^1.0.6",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c753d86..39df9f1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -75,8 +75,8 @@ importers:
specifier: ^15.0.11
version: 15.0.11
p2pt:
- specifier: ^1.5.1
- version: 1.5.1
+ specifier: github:ThaUnknown/p2pt#modernise
+ version: https://codeload.github.com/ThaUnknown/p2pt/tar.gz/9ad7a56ed6ee43f5664ebad33b803702ee349316
rollup-plugin-license:
specifier: ^3.6.0
version: 3.6.0(picomatch@4.0.2)(rollup@4.40.2)
@@ -171,6 +171,9 @@ importers:
tailwindcss:
specifier: ^3.4.17
version: 3.4.17
+ typescript:
+ specifier: ^5.8.3
+ version: 5.8.3
vaul-svelte:
specifier: ^0.3.2
version: 0.3.2(svelte@4.2.19)
@@ -644,6 +647,12 @@ packages:
'@swc/helpers@0.5.17':
resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==}
+ '@thaunknown/simple-peer@9.12.1':
+ resolution: {integrity: sha512-IS5BXvXx7cvBAzaxqotJf4s4rJCPk5JABLK6Gbnn7oAmWVcH4hYABabBBrvvJtv/xyUqR4v/H3LalnGRJJfEog==}
+
+ '@thaunknown/simple-websocket@9.1.3':
+ resolution: {integrity: sha512-pf/FCJsgWtLJiJmIpiSI7acOZVq3bIQCpnNo222UFc8Ph1lOUOTpe6LoYhhiOSKB9GUaWJEVUtZ+sK1/aBgU5Q==}
+
'@thaunknown/web-irc@1.0.1':
resolution: {integrity: sha512-oP+mrvD2U7gSXHTfT77+A+i2YVT5jp4qCbCXLrNU9aFzXdJ0iRsBbdhdT/AgeB7Nf4O+SC/wVCnwhnAfUoo0Fg==}
@@ -770,8 +779,9 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
- addr-to-ip-port@1.5.4:
- resolution: {integrity: sha512-ByxmJgv8vjmDcl3IDToxL2yrWFrRtFpZAToY0f46XFXl8zS081t7El5MXIodwm7RC6DhHBRoOSMLFSPKCtHukg==}
+ addr-to-ip-port@2.0.0:
+ resolution: {integrity: sha512-9bYbtjamtdLHZSqVIUXhilOryNPiL+x+Q5J/Unpg4VY3ZIkK3fT52UoErj1NdUeVm3J1t2iBEAur4Ywbl/bahw==}
+ engines: {node: '>=12.20.0'}
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
@@ -873,11 +883,9 @@ packages:
resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
engines: {node: '>= 0.6.0'}
- base64-js@1.5.1:
- resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
-
- bencode@2.0.3:
- resolution: {integrity: sha512-D/vrAD4dLVX23NalHwb8dSvsUsxeRPO8Y7ToKA015JQYq69MLDOMkC0uGZYA/MPpltLO8rt8eqFC2j8DxjTZ/w==}
+ bencode@4.0.0:
+ resolution: {integrity: sha512-AERXw18df0pF3ziGOCyUjqKZBVNH8HV3lBxnx5w0qtgMIk4a1wb9BkcCQbkp9Zstfrn/dzRwl7MmUHHocX3sRQ==}
+ engines: {node: '>=12.20.0'}
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
@@ -896,14 +904,11 @@ packages:
bittorrent-peerid@1.3.6:
resolution: {integrity: sha512-VyLcUjVMEOdSpHaCG/7odvCdLbAB1y3l9A2V6WIje24uV7FkJPrQrH/RrlFmKxP89pFVDEnE+YlHaFujlFIZsg==}
- bittorrent-tracker@9.19.0:
- resolution: {integrity: sha512-09d0aD2b+MC+zWvWajkUAKkYMynYW4tMbTKiRSthKtJZbafzEoNQSUHyND24SoCe3ZOb2fKfa6fu2INAESL9wA==}
- engines: {node: '>=12'}
+ bittorrent-tracker@10.0.12:
+ resolution: {integrity: sha512-EYQEwhOYkrRiiwkCFcM9pbzJInsAe7UVmUgevW133duwlZzjwf5ABwDE7pkkmNRS6iwN0b8LbI/94q16dYqiow==}
+ engines: {node: '>=12.20.0'}
hasBin: true
- bn.js@5.2.2:
- resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==}
-
bottleneck@2.19.5:
resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==}
@@ -925,9 +930,6 @@ packages:
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
- buffer@6.0.3:
- resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
-
bufferutil@4.0.9:
resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==}
engines: {node: '>=6.14.2'}
@@ -1497,9 +1499,6 @@ packages:
idb-keyval@6.2.2:
resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==}
- ieee754@1.2.1:
- resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
-
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -1893,8 +1892,9 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
- p2pt@1.5.1:
- resolution: {integrity: sha512-q1pkIKBRvGcQfv5Q3W0/c9pbBUnjcauWylc/qUZwIqcrQIxu3rfuDQXsqjwEJaBwdPNPWMY06jc5qxwVgJX6MA==}
+ p2pt@https://codeload.github.com/ThaUnknown/p2pt/tar.gz/9ad7a56ed6ee43f5664ebad33b803702ee349316:
+ resolution: {tarball: https://codeload.github.com/ThaUnknown/p2pt/tar.gz/9ad7a56ed6ee43f5664ebad33b803702ee349316}
+ version: 1.5.1
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
@@ -2034,9 +2034,6 @@ packages:
random-iterate@1.0.1:
resolution: {integrity: sha512-Jdsdnezu913Ot8qgKgSgs63XkAjEsnMcS1z+cC6D6TNXsUXsMxy0RpclF2pzGZTEiTXL9BiArdGTEexcv4nqcA==}
- randombytes@2.1.0:
- resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
-
react@19.0.0:
resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==}
engines: {node: '>=0.10.0'}
@@ -2044,10 +2041,6 @@ packages:
read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
- readable-stream@3.6.2:
- resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
- engines: {node: '>= 6'}
-
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@@ -2097,9 +2090,6 @@ packages:
run-series@1.1.9:
resolution: {integrity: sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==}
- rusha@0.8.14:
- resolution: {integrity: sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==}
-
rvfc-polyfill@1.0.7:
resolution: {integrity: sha512-seBl7J1J3/k0LuzW2T9fG6JIOpni5AbU+/87LA+zTYKgTVhsfShmS8K/yOo1eeEjGJHnAdkVAUUM+PEjN9Mpkw==}
@@ -2111,9 +2101,6 @@ packages:
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
engines: {node: '>=0.4'}
- safe-buffer@5.2.1:
- resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
-
safe-push-apply@1.0.0:
resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
engines: {node: '>= 0.4'}
@@ -2180,18 +2167,9 @@ packages:
simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
- simple-peer@9.11.1:
- resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==}
-
- simple-sha1@3.1.0:
- resolution: {integrity: sha512-ArTptMRC1v08H8ihPD6l0wesKvMfF9e8XL5rIHPanI7kGOsSsbY514MwVu6X1PITHCTB2F08zB7cyEbfc4wQjg==}
-
simple-store-svelte@1.0.6:
resolution: {integrity: sha512-39TaQ2LHRAdH+cpWPmGzDfVyoAm/uZ6UkM27O3YhUtJHk0Vw09+6/jUqprns+BgOkKxOkRetKC9SH4bbj0IZ1A==}
- simple-websocket@9.1.0:
- resolution: {integrity: sha512-8MJPnjRN6A8UCp1I+H/dSFyjwJhp6wta4hsVRhjf8w9qBHRzxYt14RaOcjvQnhD1N4yKOddEjflwMnQM4VtXjQ==}
-
sirv@3.0.1:
resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
engines: {node: '>=18'}
@@ -2262,11 +2240,9 @@ packages:
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
engines: {node: '>= 0.4'}
- string2compact@1.3.2:
- resolution: {integrity: sha512-3XUxUgwhj7Eqh2djae35QHZZT4mN3fsO7kagZhSGmhhlrQagVvWSFuuFIWnpxFS0CdTB2PlQcaL16RDi14I8uw==}
-
- string_decoder@1.3.0:
- resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+ string2compact@2.0.1:
+ resolution: {integrity: sha512-Bm/T8lHMTRXw+u83LE+OW7fXmC/wM+Mbccfdo533ajSBNxddDHlRrvxE49NdciGHgXkUQM5WYskJ7uTkbBUI0A==}
+ engines: {node: '>=12.20.0'}
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
@@ -2600,12 +2576,12 @@ packages:
bundledDependencies:
- node-pre-gyp
- ws@7.5.10:
- resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==}
- engines: {node: '>=8.3.0'}
+ ws@8.18.2:
+ resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==}
+ engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
- utf-8-validate: ^5.0.2
+ utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
@@ -3010,6 +2986,29 @@ snapshots:
dependencies:
tslib: 2.8.1
+ '@thaunknown/simple-peer@9.12.1':
+ dependencies:
+ debug: 4.4.1
+ err-code: 3.0.1
+ get-browser-rtc: 1.1.0
+ queue-microtask: 1.2.3
+ streamx: 2.22.0
+ uint8-util: 2.2.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@thaunknown/simple-websocket@9.1.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)':
+ dependencies:
+ debug: 4.4.1
+ queue-microtask: 1.2.3
+ streamx: 2.22.0
+ uint8-util: 2.2.5
+ ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
'@thaunknown/web-irc@1.0.1':
dependencies:
grapheme-splitter: 1.0.4
@@ -3165,7 +3164,7 @@ snapshots:
acorn@8.14.1: {}
- addr-to-ip-port@1.5.4: {}
+ addr-to-ip-port@2.0.0: {}
ajv@6.12.6:
dependencies:
@@ -3276,9 +3275,9 @@ snapshots:
base64-arraybuffer@1.0.2: {}
- base64-js@1.5.1: {}
-
- bencode@2.0.3: {}
+ bencode@4.0.0:
+ dependencies:
+ uint8-util: 2.2.5
binary-extensions@2.3.0: {}
@@ -3298,11 +3297,12 @@ snapshots:
bittorrent-peerid@1.3.6: {}
- bittorrent-tracker@9.19.0:
+ bittorrent-tracker@10.0.12:
dependencies:
- bencode: 2.0.3
+ '@thaunknown/simple-peer': 9.12.1
+ '@thaunknown/simple-websocket': 9.1.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)
+ bencode: 4.0.0
bittorrent-peerid: 1.3.6
- bn.js: 5.2.2
chrome-dgram: 3.0.6
clone: 2.1.2
compact2string: 1.4.1
@@ -3313,24 +3313,20 @@ snapshots:
once: 1.4.0
queue-microtask: 1.2.3
random-iterate: 1.0.1
- randombytes: 2.1.0
run-parallel: 1.2.0
run-series: 1.1.9
simple-get: 4.0.1
- simple-peer: 9.11.1
- simple-websocket: 9.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)
socks: 2.8.4
- string2compact: 1.3.2
+ string2compact: 2.0.1
+ uint8-util: 2.2.5
unordered-array-remove: 1.0.2
- ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)
+ ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)
optionalDependencies:
bufferutil: 4.0.9
utf-8-validate: 5.0.10
transitivePeerDependencies:
- supports-color
- bn.js@5.2.2: {}
-
bottleneck@2.19.5: {}
brace-expansion@1.1.11:
@@ -3356,11 +3352,6 @@ snapshots:
buffer-from@1.1.2:
optional: true
- buffer@6.0.3:
- dependencies:
- base64-js: 1.5.1
- ieee754: 1.2.1
-
bufferutil@4.0.9:
dependencies:
node-gyp-build: 4.8.4
@@ -4068,8 +4059,6 @@ snapshots:
idb-keyval@6.2.2: {}
- ieee754@1.2.1: {}
-
ignore@5.3.2: {}
ignore@7.0.4: {}
@@ -4434,11 +4423,10 @@ snapshots:
dependencies:
p-limit: 3.1.0
- p2pt@1.5.1:
+ p2pt@https://codeload.github.com/ThaUnknown/p2pt/tar.gz/9ad7a56ed6ee43f5664ebad33b803702ee349316:
dependencies:
- bittorrent-tracker: 9.19.0
- randombytes: 2.1.0
- simple-sha1: 3.1.0
+ bittorrent-tracker: 10.0.12
+ uint8-util: 2.2.5
optionalDependencies:
wrtc: 0.4.7
transitivePeerDependencies:
@@ -4551,22 +4539,12 @@ snapshots:
random-iterate@1.0.1: {}
- randombytes@2.1.0:
- dependencies:
- safe-buffer: 5.2.1
-
react@19.0.0: {}
read-cache@1.0.0:
dependencies:
pify: 2.3.0
- readable-stream@3.6.2:
- dependencies:
- inherits: 2.0.4
- string_decoder: 1.3.0
- util-deprecate: 1.0.2
-
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
@@ -4651,8 +4629,6 @@ snapshots:
run-series@1.1.9: {}
- rusha@0.8.14: {}
-
rvfc-polyfill@1.0.7: {}
sade@1.8.1:
@@ -4667,8 +4643,6 @@ snapshots:
has-symbols: 1.1.0
isarray: 2.0.5
- safe-buffer@5.2.1: {}
-
safe-push-apply@1.0.0:
dependencies:
es-errors: 1.3.0
@@ -4752,37 +4726,8 @@ snapshots:
once: 1.4.0
simple-concat: 1.0.1
- simple-peer@9.11.1:
- dependencies:
- buffer: 6.0.3
- debug: 4.4.1
- err-code: 3.0.1
- get-browser-rtc: 1.1.0
- queue-microtask: 1.2.3
- randombytes: 2.1.0
- readable-stream: 3.6.2
- transitivePeerDependencies:
- - supports-color
-
- simple-sha1@3.1.0:
- dependencies:
- queue-microtask: 1.2.3
- rusha: 0.8.14
-
simple-store-svelte@1.0.6: {}
- simple-websocket@9.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10):
- dependencies:
- debug: 4.4.1
- queue-microtask: 1.2.3
- randombytes: 2.1.0
- readable-stream: 3.6.2
- ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)
- transitivePeerDependencies:
- - bufferutil
- - supports-color
- - utf-8-validate
-
sirv@3.0.1:
dependencies:
'@polka/url': 1.0.0-next.29
@@ -4878,15 +4823,11 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
- string2compact@1.3.2:
+ string2compact@2.0.1:
dependencies:
- addr-to-ip-port: 1.5.4
+ addr-to-ip-port: 2.0.0
ipaddr.js: 2.2.0
- string_decoder@1.3.0:
- dependencies:
- safe-buffer: 5.2.1
-
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
@@ -5271,7 +5212,7 @@ snapshots:
domexception: 1.0.1
optional: true
- ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10):
+ ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10):
optionalDependencies:
bufferutil: 4.0.9
utf-8-validate: 5.0.10
diff --git a/src/app.d.ts b/src/app.d.ts
index 0ca57a3..b5b40af 100644
--- a/src/app.d.ts
+++ b/src/app.d.ts
@@ -137,9 +137,9 @@ declare global {
}
}
- declare module '*.svelte' {
- export default SvelteComponentTyped
- }
+ // declare module '*.svelte' {
+ // export default SvelteComponentTyped
+ // }
}
declare module '*.svelte' {
diff --git a/src/app.html b/src/app.html
index e087120..3464714 100644
--- a/src/app.html
+++ b/src/app.html
@@ -3,6 +3,7 @@
+ Hayase
%sveltekit.head%
diff --git a/src/lib/components/ui/chat/Messages.svelte b/src/lib/components/ui/chat/Messages.svelte
index 3711923..543f1b4 100644
--- a/src/lib/components/ui/chat/Messages.svelte
+++ b/src/lib/components/ui/chat/Messages.svelte
@@ -1,6 +1,5 @@
@@ -27,13 +16,13 @@
{processed.length} Member(s)
- {#each processed as { id, pfp, nick } (id)}
+ {#each processed as [key, user] (key)}
-

+
- {nick}
+ {user.name}
-
native.openURL('https://anilist.co/user/' + id)}>
+ native.openURL('https://anilist.co/user/' + user.id)}>
diff --git a/src/lib/components/ui/chat/index.ts b/src/lib/components/ui/chat/index.ts
index a6bef22..81d6b12 100644
--- a/src/lib/components/ui/chat/index.ts
+++ b/src/lib/components/ui/chat/index.ts
@@ -1,11 +1,7 @@
-export type UserType = 'al' | 'guest'
+import type { Viewer } from '$lib/modules/anilist/queries'
+import type { ResultOf } from 'gql.tada'
-export interface ChatUser {
- nick: string
- id: string
- pfpid: string
- type: UserType
-}
+export type ChatUser = Omit
['Viewer']>, 'id'> & { id: string | number }
export interface ChatMessage {
message: string
@@ -14,13 +10,5 @@ export interface ChatMessage {
date: Date
}
-export function getPFP (user: ChatUser) {
- if (user.type === 'al') {
- return `https://s4.anilist.co/file/anilistcdn/user/avatar/medium/b${user.id}-${user.pfpid}`
- } else {
- return 'https://s4.anilist.co/file/anilistcdn/user/avatar/medium/default.png'
- }
-}
-
export { default as UserList } from './UserList.svelte'
export { default as Messages } from './Messages.svelte'
diff --git a/src/lib/components/ui/irc/interface.svelte b/src/lib/components/ui/irc/interface.svelte
new file mode 100644
index 0000000..096249e
--- /dev/null
+++ b/src/lib/components/ui/irc/interface.svelte
@@ -0,0 +1,61 @@
+
+
+
diff --git a/src/lib/components/ui/irc/irc.svelte b/src/lib/components/ui/irc/irc.svelte
index 3e2da29..1160aa2 100644
--- a/src/lib/components/ui/irc/irc.svelte
+++ b/src/lib/components/ui/irc/irc.svelte
@@ -1,10 +1,6 @@
{#if $irc}
@@ -69,26 +42,6 @@
Loading...
{:then client}
-
-
-
-
-
-
-
-
-
-
-
-
-
+
{/await}
{/if}
diff --git a/src/lib/components/ui/player/mediahandler.svelte b/src/lib/components/ui/player/mediahandler.svelte
index 56d79c8..e89d3b7 100644
--- a/src/lib/components/ui/player/mediahandler.svelte
+++ b/src/lib/components/ui/player/mediahandler.svelte
@@ -9,6 +9,7 @@
import { fillerEpisodes } from '$lib/components/EpisodesList.svelte'
import { cover, episodes, title } from '$lib/modules/anilist'
import { settings } from '$lib/modules/settings'
+ import { w2globby } from '$lib/modules/w2g/lobby'
export let mediaInfo: NonNullable>>
@@ -27,6 +28,14 @@
let current = fileToMedaInfo(mediaInfo.target)
+ $: $w2globby?.mediaIndexChanged(mediaInfo.resolvedFiles.indexOf(current.file))
+ $: $w2globby?.on('index', index => {
+ const file = mediaInfo.resolvedFiles[index]
+ if (file) {
+ current = fileToMedaInfo(file)
+ }
+ })
+
function findEpisode (episode: number) {
return mediaInfo.targetAnimeFiles.find(file => file.metadata.episode === episode)
}
@@ -70,6 +79,7 @@
function selectFile (file: ResolvedFile) {
current = fileToMedaInfo(file)
+ $w2globby?.mediaIndexChanged(mediaInfo.resolvedFiles.indexOf(current.file))
}
$: next = hasNext(current)
diff --git a/src/lib/components/ui/player/player.svelte b/src/lib/components/ui/player/player.svelte
index 2141923..74439d2 100644
--- a/src/lib/components/ui/player/player.svelte
+++ b/src/lib/components/ui/player/player.svelte
@@ -57,6 +57,7 @@
import { click } from '$lib/modules/navigate'
import { settings } from '$lib/modules/settings'
import { server } from '$lib/modules/torrent'
+ import { w2globby } from '$lib/modules/w2g/lobby'
import { toTS, fastPrettyBits } from '$lib/utils'
export let mediaInfo: MediaInfo
@@ -652,6 +653,12 @@
return { destroy: () => ctrl.abort() }
}
+
+ $: $w2globby?.playerStateChanged({ paused, time: Math.floor(currentTime) })
+ $: $w2globby?.on('player', state => {
+ currentTime = state.time
+ paused = state.paused
+ })
diff --git a/src/lib/components/ui/sidebar/sidebarlist.svelte b/src/lib/components/ui/sidebar/sidebarlist.svelte
index 1cb5f2c..f01b152 100644
--- a/src/lib/components/ui/sidebar/sidebarlist.svelte
+++ b/src/lib/components/ui/sidebar/sidebarlist.svelte
@@ -44,8 +44,7 @@
-
-
+
@@ -55,7 +54,6 @@
diff --git a/src/lib/modules/irc.ts b/src/lib/modules/irc.ts
index 43d918b..a299705 100644
--- a/src/lib/modules/irc.ts
+++ b/src/lib/modules/irc.ts
@@ -1,5 +1,3 @@
-import { EventEmitter } from 'events'
-
import Client, { createChannelConstructor } from '@thaunknown/web-irc'
import { writable } from 'simple-store-svelte'
@@ -7,6 +5,23 @@ import { decryptMessage, encryptMessage } from './crypt'
import type { ChatMessage, ChatUser } from '$lib/components/ui/chat'
import type IrcChannel from '@thaunknown/web-irc/channel'
+import type IrcClient from '@thaunknown/web-irc/client'
+import type { EventEmitter } from 'events'
+
+export type UserType = 'al' | 'guest'
+export interface IRCChatUser {
+ nick: string
+ id: string
+ pfpid: string
+ type: UserType
+}
+export function getPFP (user: Pick) {
+ if (user.type === 'al') {
+ return `https://s4.anilist.co/file/anilistcdn/user/avatar/medium/b${user.id}-${user.pfpid}`
+ } else {
+ return 'https://s4.anilist.co/file/anilistcdn/user/avatar/medium/default.png'
+ }
+}
export interface IRCUser { nick: string, ident: string, hostname: string, modes: string[], tags: object }
export interface PrivMessage {
@@ -24,30 +39,48 @@ export interface PrivMessage {
time: number
}
-export default class MessageClient extends EventEmitter {
- irc = new Client(null)
+// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
+type IRCEvents = {
+ userlist: [{ users: IRCUser[] }]
+ join: [IRCUser]
+ part: [IRCUser]
+ quit: [IRCUser]
+ kick: [IRCUser]
+ privmsg: [PrivMessage]
+ connected: []
+}
+
+function ircUserToChatUser ({ id, pfpid, type, nick }: IRCChatUser): ChatUser {
+ return { id, avatar: { medium: getPFP({ id, pfpid, type }) }, name: nick, mediaListOptions: null }
+}
+
+function ircIdentToChatUser (user: IRCUser): ChatUser {
+ const [nick, pfpid, pfpex] = user.nick.split('_') as [string, string, string]
+ const [type, id] = user.ident.split('_') as ['al' | 'guest', string]
+ return ircUserToChatUser({ id, pfpid: `${pfpid}.${pfpex}`, type, nick })
+}
+
+export default class MessageClient {
+ irc = new Client(null) as IrcClient & EventEmitter
users = writable>({})
messages = writable([])
channel?: IrcChannel
ident
- constructor (ident: ChatUser) {
- super()
+ constructor (ident: IRCChatUser) {
this.ident = ident
- this.irc.on('userlist', async ({ users }: { users: IRCUser[] }) => {
- this.users.value = users.reduce((acc, user) => {
- const [nick, pfpid, pfpex] = user.nick.split('_') as [string, string, string]
- const [type, id] = user.ident.split('_') as ['al' | 'guest', string]
- acc[user.ident] = { nick, id, pfpid: `${pfpid}.${pfpex}`, type }
+ this.irc.on('userlist', async ({ users }) => {
+ this.users.value = users.reduce((acc, ircuser) => {
+ const user = ircIdentToChatUser(ircuser)
+ acc[ircuser.ident] = user
return acc
}, this.users.value)
})
- this.irc.on('join', async (user: IRCUser) => {
+ this.irc.on('join', async ircuser => {
try {
- const [nick, pfpid, pfpex] = user.nick.split('_') as [string, string, string]
- const [type, id] = user.ident.split('_') as ['al' | 'guest', string]
- this.users.value[user.ident] = { nick, id, pfpid: `${pfpid}.${pfpex}`, type }
+ const user = ircIdentToChatUser(ircuser)
+ this.users.value[ircuser.ident] = user
this.users.update(users => users)
} catch (error) {
console.error(error)
@@ -63,9 +96,9 @@ export default class MessageClient extends EventEmitter {
this.irc.on('part', deleteUser)
this.irc.on('kick', deleteUser)
- this.irc.on('privmsg', async (priv: PrivMessage) => {
- const message = await decryptMessage(priv.message)
+ this.irc.on('privmsg', async priv => {
try {
+ const message = await decryptMessage(priv.message)
this.messages.update(messages => [...messages, {
message,
user: this.users.value[priv.ident]!,
@@ -83,17 +116,17 @@ export default class MessageClient extends EventEmitter {
const encrypted = await encryptMessage(message)
this.channel!.say(encrypted)
this.messages.update(messages => [...messages, {
- user: this.ident,
+ user: ircUserToChatUser(this.ident),
message,
date: new Date(),
type: 'outgoing'
}])
}
- static async new ({ nick, id, pfpid, type }: ChatUser) {
+ static async new ({ nick, id, pfpid, type }: IRCChatUser) {
const client = new this({ nick, id, pfpid, type })
- await new Promise(resolve => {
+ await new Promise(resolve => {
client.irc.once('connected', resolve)
client.irc.connect({
version: null,
diff --git a/src/lib/modules/torrent/client.ts b/src/lib/modules/torrent/client.ts
index 87c3672..235f776 100644
--- a/src/lib/modules/torrent/client.ts
+++ b/src/lib/modules/torrent/client.ts
@@ -3,6 +3,7 @@ import { get } from 'svelte/store'
import { persisted } from 'svelte-persisted-store'
import native from '../native'
+import { w2globby } from '../w2g/lobby'
import type { TorrentFile, TorrentInfo } from '../../../app'
import type { Media } from '../anilist'
@@ -53,6 +54,7 @@ export const server = new class ServerClient {
play (id: string, media: Media, episode: number) {
this.last.set({ id, media, episode })
this.active.value = this._play(id, media, episode)
+ w2globby.value?.mediaChange({ episode, mediaId: media.id, torrent: id })
return this.active.value
}
diff --git a/src/lib/modules/w2g/events.ts b/src/lib/modules/w2g/events.ts
index b693977..3444fc4 100644
--- a/src/lib/modules/w2g/events.ts
+++ b/src/lib/modules/w2g/events.ts
@@ -1,16 +1,23 @@
-export default class Event {
- payload
- type = ''
- constructor (type: string, payload: T) {
+import type { ChatUser } from '$lib/components/ui/chat'
+
+export default class Event {
+ readonly type: K
+ readonly payload: W2GEvents[K]
+
+ constructor (type: K, payload: W2GEvents[K]) {
this.type = type
this.payload = payload
}
}
-export const EventTypes = {
- SessionInitEvent: 'init',
- MagnetLinkEvent: 'magnet',
- MediaIndexEvent: 'index',
- PlayerStateEvent: 'player',
- MessageEvent: 'message'
+export interface PlayerState { paused: boolean, time: number }
+
+export interface MediaState { torrent: string, mediaId: number, episode: number }
+
+export interface W2GEvents {
+ init: ChatUser
+ media?: MediaState
+ index?: number
+ player: PlayerState
+ message: string
}
diff --git a/src/lib/modules/w2g/index.ts b/src/lib/modules/w2g/index.ts
index 23bb977..f2c9bb9 100644
--- a/src/lib/modules/w2g/index.ts
+++ b/src/lib/modules/w2g/index.ts
@@ -5,15 +5,15 @@ import P2PT, { type Peer } from 'p2pt'
import { writable } from 'simple-store-svelte'
import client from '../anilist/client.js'
+import { server } from '../torrent'
-import Event, { EventTypes } from './events.js'
+import Event, { type MediaState, type PlayerState, type W2GEvents } from './events.js'
-import type { Viewer } from '../anilist/queries'
-import type { ResultOf } from 'gql.tada'
+import type { ChatMessage, ChatUser } from '$lib/components/ui/chat'
const debug = Debug('ui:w2g')
-function generateRandomHexCode (len: number) {
+export function generateRandomHexCode (len: number) {
let hexCode = ''
while (hexCode.length < len) {
@@ -23,73 +23,77 @@ function generateRandomHexCode (len: number) {
return hexCode
}
-type PeerList = Record['Viewer'] | {id: string }, peer?: Peer }>
+type AppEvent = {
+ [K in keyof W2GEvents]-?: Event
+}[keyof W2GEvents]
-interface PlayerState {paused: boolean, time: number}
+type PeerList = Record
-export class W2GClient extends EventEmitter {
- static readonly #announce = [
- atob('d3NzOi8vdHJhY2tlci5vcGVud2VidG9ycmVudC5jb20='),
- atob('d3NzOi8vdHJhY2tlci53ZWJ0b3JyZW50LmRldg=='),
- atob('d3NzOi8vdHJhY2tlci5maWxlcy5mbTo3MDczL2Fubm91bmNl'),
- atob('d3NzOi8vdHJhY2tlci5idG9ycmVudC54eXov')
- ]
+const ANNOUNCE = [
+ atob('d3NzOi8vdHJhY2tlci5vcGVud2VidG9ycmVudC5jb20='),
+ atob('d3NzOi8vdHJhY2tlci53ZWJ0b3JyZW50LmRldg=='),
+ atob('d3NzOi8vdHJhY2tlci5maWxlcy5mbTo3MDczL2Fubm91bmNl'),
+ atob('d3NzOi8vdHJhY2tlci5idG9ycmVudC54eXov')
+]
+export class W2GClient extends EventEmitter<{index: [number], player: [PlayerState]}> {
player: PlayerState = {
paused: true,
time: 0
}
index = 0
- magnet: {magnet: string, hash: string} | null = null
- isHost = false
- #p2pt: P2PT | null
+ media: MediaState | undefined
+ isHost
+ readonly #p2pt
code
- messages = writable['Viewer'] | {id: string }, type: 'incoming' | 'outgoing', date: Date}>>([])
+ messages = writable([])
- self = client.viewer.value?.viewer ?? { id: generateRandomHexCode(16) }
- /** @type {import('simple-store-svelte').Writable} */
+ self: ChatUser = client.viewer.value?.viewer ?? { id: generateRandomHexCode(16), avatar: null, mediaListOptions: null, name: 'Guest' }
peers = writable({ [this.self.id]: { user: this.self } })
get inviteLink () {
- return `https://miru.watch/w2g/${this.code}`
+ return `https://hayas.ee/w2g/${this.code}`
}
- localMediaIndexChanged (index: number) {
- this.index = index
-
- this.mediaIndexChanged(index)
- }
-
- localPlayerStateChanged ({ payload }: Event) {
- debug(`localPlayerStateChanged: ${JSON.stringify(payload)}`)
- this.player.paused = payload.paused
- this.player.time = payload.time
-
- this.playerStateChanged(this.player)
- }
-
- constructor (code?: string) {
+ constructor (code: string, isHost: boolean) {
super()
- this.isHost = !code
+ this.isHost = isHost
- this.code = code ?? generateRandomHexCode(16)
+ this.code = code
debug(`W2GClient: ${this.code}, ${this.isHost}`)
- this.#p2pt = new P2PT(W2GClient.#announce, this.code)
+ this.#p2pt = new P2PT(ANNOUNCE, this.code)
+
+ this.#p2pt.on('peerconnect', peer => {
+ debug(`peerconnect: ${peer.id}`)
+ this._sendEvent(peer, new Event('init', this.self))
+
+ if (this.isHost) this._sendInitialSessionState(peer)
+ })
+
+ this.#p2pt.on('peerclose', peer => {
+ debug(`peerclose: ${peer.id}`)
+ this.peers.update(peers => {
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
+ delete peers[peer.id]
+ return peers
+ })
+ })
+
+ this.#p2pt.on('msg', this._onMsg)
- this.#wireEvents()
this.#p2pt.start()
}
- magnetLink (magnet: { hash: string, magnet: string }) {
- debug(`magnetLink: ${this.magnet?.hash} ${magnet.hash}`)
- if (this.magnet?.hash !== magnet.hash) {
- this.magnet = magnet
+ mediaChange (media: MediaState) {
+ debug(`mediaChange: ${this.media?.torrent} ${media.torrent}`)
+ if (this.media?.torrent !== media.torrent) {
+ this.media = media
this.isHost = true
- this.#sendToPeers(new Event('magnet', magnet))
+ this._sendToPeers(new Event('media', media))
}
}
@@ -97,7 +101,7 @@ export class W2GClient extends EventEmitter {
debug(`mediaIndexChanged: ${this.index} ${index}`)
if (this.index !== index) {
this.index = index
- this.#sendToPeers(new Event('index', index))
+ this._sendToPeers(new Event('index', index))
}
}
@@ -112,7 +116,7 @@ export class W2GClient extends EventEmitter {
playerStateChanged (state: PlayerState) {
debug(`playerStateChanged: ${JSON.stringify(state)}`)
- if (this._playerStateChanged(state)) this.#sendToPeers(new Event('player', state))
+ if (this._playerStateChanged(state)) this._sendToPeers(new Event('player', state))
}
message (message: string) {
@@ -123,77 +127,61 @@ export class W2GClient extends EventEmitter {
type: 'outgoing',
date: new Date()
})])
- this.#sendToPeers(new Event('message', message))
+ this._sendToPeers(new Event('message', message))
}
- #wireEvents () {
- this.#p2pt?.on('peerconnect', this.#onPeerconnect.bind(this))
- this.#p2pt?.on('msg', this.#onMsg.bind(this))
- this.#p2pt?.on('peerclose', this.#onPeerclose.bind(this))
+ _sendEvent (peer: Peer, event: Event) {
+ debug(`sendEvent: ${peer.id} ${JSON.stringify(event)}`)
+ this.#p2pt.send(peer, event)
}
- #sendEvent (peer: Peer, event: Event) {
- debug(`#sendEvent: ${peer.id} ${JSON.stringify(event)}`)
- this.#p2pt?.send(peer, JSON.stringify(event))
+ _sendInitialSessionState (peer: Peer) {
+ this._sendEvent(peer, new Event('media', this.media))
+ this._sendEvent(peer, new Event('index', this.index))
+ this._sendEvent(peer, new Event('player', this.player))
}
- #sendInitialSessionState (peer: Peer) {
- this.#sendEvent(peer, new Event('magnet', this.magnet))
- this.#sendEvent(peer, new Event('index', this.index))
- this.#sendEvent(peer, new Event('player', this.player))
- }
-
- async #onPeerconnect (peer: Peer) {
- debug(`#onPeerconnect: ${peer.id}`)
- this.#sendEvent(peer, new Event('init', this.self))
-
- if (this.isHost) this.#sendInitialSessionState(peer)
- }
-
- #onMsg (peer: Peer, data: Event['Viewer'] | {index: number}> | string) {
- debug(`#onMsg: ${peer.id} ${JSON.stringify(data)}`)
- data = typeof data === 'string' ? JSON.parse(data) as Event['Viewer'] | {index: number}> : data
+ _onMsg = async (peer: Peer, data: AppEvent) => {
+ debug(`onMsg: ${peer.id} ${JSON.stringify(data)}`)
switch (data.type) {
- case EventTypes.SessionInitEvent:
+ case 'init':
this.peers.update(peers => {
peers[peer.id] = {
peer,
- user: data.payload as ResultOf['Viewer']
+ user: data.payload
}
return peers
})
break
- case EventTypes.MagnetLinkEvent: {
- const cast = data as Event<{magnet: string, hash: string}>
- if (cast.payload.magnet === undefined) break
- const { hash, magnet } = cast.payload
- if (hash !== this.magnet?.hash) {
+ case 'media': {
+ if (data.payload?.torrent == null || data.payload?.mediaId == null) break
+ const { torrent, mediaId, episode } = data.payload
+ if (torrent !== this.media?.torrent) {
this.isHost = false
- this.magnet = cast.payload
- add(magnet)
+ this.media = data.payload
+ const media = (await client.single(mediaId)).data?.Media
+ if (media == null) break
+ server.play(torrent, media, episode)
}
break
}
- case EventTypes.MediaIndexEvent: {
- const cast = data as Event<{index: number}>
- if (cast.payload.index === undefined) break
- if (this.index !== cast.payload.index) {
- this.index = cast.payload.index
- this.emit('index', cast.payload.index)
+ case 'index': {
+ if (data.payload == null) break
+ if (this.index !== data.payload) {
+ this.index = data.payload
+ this.emit('index', data.payload)
}
break
}
- case EventTypes.PlayerStateEvent: {
- const cast = data as Event
- if (cast.payload.time === undefined) break
- if (this._playerStateChanged(cast.payload)) this.emit('player', data.payload)
+ case 'player': {
+ if (data.payload?.time == null) break
+ if (this._playerStateChanged(data.payload)) this.emit('player', data.payload)
break
}
- case EventTypes.MessageEvent:{
- const cast = data as Event
- this.messages.update(messages => [...messages, ({ message: cast.payload, user: this.peers.value[peer.id].user, type: 'incoming', date: new Date() })])
+ case 'message': {
+ this.messages.update(messages => [...messages, ({ message: data.payload, user: this.peers.value[peer.id]!.user, type: 'incoming', date: new Date() })])
break
}
default:
@@ -201,27 +189,16 @@ export class W2GClient extends EventEmitter {
}
}
- #onPeerclose (peer: Peer) {
- debug(`#onPeerclose: ${peer.id}`)
- this.peers.update(peers => {
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
- delete peers[peer.id]
- return peers
- })
- }
-
- #sendToPeers (event: Event) {
- if (!this.#p2pt) return
+ _sendToPeers (event: Event) {
for (const { peer } of Object.values(this.peers.value)) {
- if (peer) this.#sendEvent(peer, event)
+ if (peer) this._sendEvent(peer, event)
}
}
destroy () {
debug('destroy')
- this.#p2pt?.destroy()
+ this.#p2pt.destroy()
this.removeAllListeners()
- this.#p2pt = null
this.isHost = false
this.peers.value = {}
}
diff --git a/src/lib/modules/w2g/lobby.ts b/src/lib/modules/w2g/lobby.ts
new file mode 100644
index 0000000..a0b7c78
--- /dev/null
+++ b/src/lib/modules/w2g/lobby.ts
@@ -0,0 +1,5 @@
+import { writable } from 'simple-store-svelte'
+
+import type { W2GClient } from '.'
+
+export const w2globby = writable()
diff --git a/src/routes/app/search/+page.svelte b/src/routes/app/search/+page.svelte
index bcca67d..3accdd6 100644
--- a/src/routes/app/search/+page.svelte
+++ b/src/routes/app/search/+page.svelte
@@ -2,6 +2,7 @@
import FileImage from 'lucide-svelte/icons/file-image'
import Trash from 'lucide-svelte/icons/trash'
import X from 'lucide-svelte/icons/x'
+ import { tick } from 'svelte'
import MagnifyingGlass from 'svelte-radix/MagnifyingGlass.svelte'
import { toast } from 'svelte-sonner'
@@ -10,6 +11,7 @@
import type { Search } from '$lib/modules/anilist/queries'
import type { VariablesOf } from 'gql.tada'
+ import { replaceState } from '$app/navigation'
import { page } from '$app/stores'
import { badgeVariants } from '$lib/components/ui/badge'
import { Button } from '$lib/components/ui/button'
@@ -93,6 +95,8 @@
onList: [] as format[]
}
+ $: console.log('search updated', search)
+
let pageNumber = 1
let inputText = ''
@@ -123,7 +127,7 @@
}
function searchQuery (filter: Partial, page: number) {
- return client.search({
+ const search = {
page,
ids: filter.ids,
search: filter.name,
@@ -134,7 +138,11 @@
format: filter.formats?.map(f => f.value) as Array<'MUSIC' | 'MANGA' | 'TV' | 'TV_SHORT' | 'MOVIE' | 'SPECIAL' | 'OVA' | 'ONA' | 'NOVEL' | 'ONE_SHOT'>,
status: filter.status?.map(s => s.value) as Array<'FINISHED' | 'RELEASING' | 'NOT_YET_RELEASED' | 'CANCELLED' | 'HIATUS' | null>,
sort: [filter.sort?.[0]?.value ?? 'SEARCH_MATCH'] as Array<'TITLE_ROMAJI_DESC' | 'ID' | 'START_DATE_DESC' | 'SCORE_DESC' | 'POPULARITY_DESC' | 'TRENDING_DESC' | 'UPDATED_AT_DESC' | 'ID_DESC' | 'TITLE_ROMAJI' | 'TITLE_ENGLISH' | 'TITLE_ENGLISH_DESC' | null>
- })
+ }
+
+ tick().then(() => replaceState('', { search }))
+
+ return client.search(search)
}
const updateText = debounce((e: FormInputEvent) => {
diff --git a/src/routes/app/w2g/+page.svelte b/src/routes/app/w2g/+page.svelte
deleted file mode 100644
index e69de29..0000000
diff --git a/src/routes/app/w2g/+page.ts b/src/routes/app/w2g/+page.ts
new file mode 100644
index 0000000..d167cdc
--- /dev/null
+++ b/src/routes/app/w2g/+page.ts
@@ -0,0 +1,10 @@
+import { redirect } from '@sveltejs/kit'
+
+import { generateRandomHexCode, W2GClient } from '$lib/modules/w2g'
+import { w2globby } from '$lib/modules/w2g/lobby'
+
+export function load () {
+ w2globby.value ??= new W2GClient(generateRandomHexCode(16), true)
+
+ redirect(302, '/app/w2g/' + w2globby.value.code)
+}
diff --git a/src/routes/app/w2g/[id]/+page.svelte b/src/routes/app/w2g/[id]/+page.svelte
new file mode 100644
index 0000000..1a0b0c3
--- /dev/null
+++ b/src/routes/app/w2g/[id]/+page.svelte
@@ -0,0 +1,60 @@
+
+
+
+
+
diff --git a/src/routes/app/w2g/[id]/+page.ts b/src/routes/app/w2g/[id]/+page.ts
new file mode 100644
index 0000000..0358c7c
--- /dev/null
+++ b/src/routes/app/w2g/[id]/+page.ts
@@ -0,0 +1,5 @@
+import type { PageLoad } from './$types'
+
+export const load: PageLoad = ({ params }) => {
+ return params
+}
diff --git a/vite.config.ts b/vite.config.ts
index 222ab69..fd8f62b 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -25,6 +25,8 @@ export default defineConfig({
'./Scripts': resolve(__dirname, 'src/patches/empty.cjs'),
// yeah they dont export this for making custom icons, sucks
'lucide-svelte/dist/Icon.svelte': resolve(__dirname, 'node_modules/lucide-svelte/dist/Icon.svelte'),
+ // no exports :/
+ 'bittorrent-tracker/lib/client/websocket-tracker.js': resolve(__dirname, 'node_modules/bittorrent-tracker/lib/client/websocket-tracker.js'),
}
},
server: { port: 7344 },