Compare commits
8
Commits
acb0cd3161
...
random-bs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37cfb375b8
|
||
|
|
ea3d92974b
|
||
|
|
0cb2a7739a
|
||
|
|
5d82e92461
|
||
|
|
151c719901
|
||
|
|
f7636f61a7
|
||
|
|
707ba4cdf2
|
||
|
|
1a20111501
|
@@ -4,6 +4,9 @@
|
|||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "space-stream",
|
"name": "space-stream",
|
||||||
|
"dependencies": {
|
||||||
|
"jassub": "^2.4.2",
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/adapter-auto": "^7.0.0",
|
"@sveltejs/adapter-auto": "^7.0.0",
|
||||||
"@sveltejs/adapter-cloudflare": "^7.2.8",
|
"@sveltejs/adapter-cloudflare": "^7.2.8",
|
||||||
@@ -272,6 +275,8 @@
|
|||||||
|
|
||||||
"@types/trusted-types": ["@types/[email protected]", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
|
"@types/trusted-types": ["@types/[email protected]", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
|
||||||
|
|
||||||
|
"abslink": ["[email protected]", "", {}, "sha512-8fQgnUoVSgc1IhOrYzdDY+wTDPktbuYjds2LKf9kWYWKwDnHgXU168gdV3sPei7vevFf5m2fPZ6IQSKZkSjHVg=="],
|
||||||
|
|
||||||
"acorn": ["[email protected]", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
|
"acorn": ["[email protected]", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
|
||||||
|
|
||||||
"aria-query": ["[email protected]", "", {}, "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g=="],
|
"aria-query": ["[email protected]", "", {}, "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g=="],
|
||||||
@@ -314,10 +319,14 @@
|
|||||||
|
|
||||||
"is-reference": ["[email protected]", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
|
"is-reference": ["[email protected]", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
|
||||||
|
|
||||||
|
"jassub": ["[email protected]", "", { "dependencies": { "abslink": "^1.1.6", "lfa-ponyfill": "^1.1.0", "rvfc-polyfill": "^1.0.8", "throughput": "^1.0.2" } }, "sha512-qWECKZWADUYAlXrzTEKPw+zY06XNy4tuZhTTWyk/ML+axRSMuOcbI0tAxL6tdXg+wdROd+EZU83SQFh/frugCg=="],
|
||||||
|
|
||||||
"jiti": ["[email protected]", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
"jiti": ["[email protected]", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
||||||
|
|
||||||
"kleur": ["[email protected]", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
|
"kleur": ["[email protected]", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
|
||||||
|
|
||||||
|
"lfa-ponyfill": ["[email protected]", "", {}, "sha512-YS3/DmyDdywWwoEu1ZacAudqkJ4q7WtKE9+bWlaSuEoVrXva7ChIJHMJYs19zyVc1H198pzqAreQU0r/+YNeew=="],
|
||||||
|
|
||||||
"lightningcss": ["[email protected]", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
|
"lightningcss": ["[email protected]", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
|
||||||
|
|
||||||
"lightningcss-android-arm64": ["[email protected]", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
|
"lightningcss-android-arm64": ["[email protected]", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
|
||||||
@@ -382,6 +391,8 @@
|
|||||||
|
|
||||||
"rollup": ["[email protected]", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="],
|
"rollup": ["[email protected]", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="],
|
||||||
|
|
||||||
|
"rvfc-polyfill": ["[email protected]", "", {}, "sha512-uA+0wwTkZ4OT8v45pfDfH+7Yq8mY6MvNngiF5Sq6VBgjJsvsfgt7Q18cyZqZjfAhW9rhkgXPX0cW0R9uw7yElA=="],
|
||||||
|
|
||||||
"sade": ["[email protected]", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
|
"sade": ["[email protected]", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
|
||||||
|
|
||||||
"safe-stable-stringify": ["[email protected]", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
|
"safe-stable-stringify": ["[email protected]", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
|
||||||
@@ -410,6 +421,8 @@
|
|||||||
|
|
||||||
"tapable": ["[email protected]", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="],
|
"tapable": ["[email protected]", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="],
|
||||||
|
|
||||||
|
"throughput": ["[email protected]", "", {}, "sha512-jvK1ZXuhsggjb3qYQjMiU/AVYYiTeqT5thWvYR2yuy2LGM84P5MSSyAinwHahGsdBYKR9m9HncVR/3f3nFKkxg=="],
|
||||||
|
|
||||||
"tinyglobby": ["[email protected]", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
|
"tinyglobby": ["[email protected]", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
|
||||||
|
|
||||||
"totalist": ["[email protected]", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
|
"totalist": ["[email protected]", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
|
||||||
|
|||||||
@@ -36,5 +36,8 @@
|
|||||||
"vite": "^7.3.1",
|
"vite": "^7.3.1",
|
||||||
"vite-plugin-devtools-json": "^1.0.0",
|
"vite-plugin-devtools-json": "^1.0.0",
|
||||||
"wrangler": "^4.81.1"
|
"wrangler": "^4.81.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jassub": "^2.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const spacetimedb = schema({
|
|||||||
{
|
{
|
||||||
id: t.u64().primaryKey(),
|
id: t.u64().primaryKey(),
|
||||||
url: t.string(),
|
url: t.string(),
|
||||||
|
subtitleUrl: t.string(),
|
||||||
timePosition: t.f64(),
|
timePosition: t.f64(),
|
||||||
isPlaying: t.bool(),
|
isPlaying: t.bool(),
|
||||||
lastUpdatedAt: t.timestamp(),
|
lastUpdatedAt: t.timestamp(),
|
||||||
@@ -19,6 +20,7 @@ export const init = spacetimedb.init((ctx) => {
|
|||||||
ctx.db.videoState.insert({
|
ctx.db.videoState.insert({
|
||||||
id: 1n,
|
id: 1n,
|
||||||
url: "https://cdn.cazzzer.com/LycoReco08.mkv",
|
url: "https://cdn.cazzzer.com/LycoReco08.mkv",
|
||||||
|
subtitleUrl: "",
|
||||||
timePosition: 0.0,
|
timePosition: 0.0,
|
||||||
isPlaying: false,
|
isPlaying: false,
|
||||||
lastUpdatedAt: ctx.timestamp,
|
lastUpdatedAt: ctx.timestamp,
|
||||||
@@ -34,6 +36,7 @@ export const set_url = spacetimedb.reducer({ url: t.string() }, (ctx, { url }) =
|
|||||||
ctx.db.videoState.id.update({
|
ctx.db.videoState.id.update({
|
||||||
...row,
|
...row,
|
||||||
url,
|
url,
|
||||||
|
subtitleUrl: "", // Clear subtitle on new video
|
||||||
timePosition: 0.0,
|
timePosition: 0.0,
|
||||||
isPlaying: false,
|
isPlaying: false,
|
||||||
lastUpdatedAt: ctx.timestamp,
|
lastUpdatedAt: ctx.timestamp,
|
||||||
@@ -71,3 +74,13 @@ export const seek = spacetimedb.reducer({ time_position: t.f64() }, (ctx, { time
|
|||||||
lastUpdatedAt: ctx.timestamp,
|
lastUpdatedAt: ctx.timestamp,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const set_subtitle_url = spacetimedb.reducer({ url: t.string() }, (ctx, { url }) => {
|
||||||
|
const row = ctx.db.videoState.id.find(1n);
|
||||||
|
if (!row) return;
|
||||||
|
ctx.db.videoState.id.update({
|
||||||
|
...row,
|
||||||
|
subtitleUrl: url,
|
||||||
|
lastUpdatedAt: ctx.timestamp,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -37,6 +37,7 @@ import {
|
|||||||
import PauseReducer from "./pause_reducer";
|
import PauseReducer from "./pause_reducer";
|
||||||
import PlayReducer from "./play_reducer";
|
import PlayReducer from "./play_reducer";
|
||||||
import SeekReducer from "./seek_reducer";
|
import SeekReducer from "./seek_reducer";
|
||||||
|
import SetSubtitleUrlReducer from "./set_subtitle_url_reducer";
|
||||||
import SetUrlReducer from "./set_url_reducer";
|
import SetUrlReducer from "./set_url_reducer";
|
||||||
|
|
||||||
// Import all procedure arg schemas
|
// Import all procedure arg schemas
|
||||||
@@ -66,6 +67,7 @@ const reducersSchema = __reducers(
|
|||||||
__reducerSchema("pause", PauseReducer),
|
__reducerSchema("pause", PauseReducer),
|
||||||
__reducerSchema("play", PlayReducer),
|
__reducerSchema("play", PlayReducer),
|
||||||
__reducerSchema("seek", SeekReducer),
|
__reducerSchema("seek", SeekReducer),
|
||||||
|
__reducerSchema("set_subtitle_url", SetSubtitleUrlReducer),
|
||||||
__reducerSchema("set_url", SetUrlReducer),
|
__reducerSchema("set_url", SetUrlReducer),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||||
|
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
/* tslint:disable */
|
||||||
|
import {
|
||||||
|
TypeBuilder as __TypeBuilder,
|
||||||
|
t as __t,
|
||||||
|
type AlgebraicTypeType as __AlgebraicTypeType,
|
||||||
|
type Infer as __Infer,
|
||||||
|
} from "spacetimedb";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
url: __t.string(),
|
||||||
|
};
|
||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
export const VideoState = __t.object("VideoState", {
|
export const VideoState = __t.object("VideoState", {
|
||||||
id: __t.u64(),
|
id: __t.u64(),
|
||||||
url: __t.string(),
|
url: __t.string(),
|
||||||
|
subtitleUrl: __t.string(),
|
||||||
timePosition: __t.f64(),
|
timePosition: __t.f64(),
|
||||||
isPlaying: __t.bool(),
|
isPlaying: __t.bool(),
|
||||||
lastUpdatedAt: __t.timestamp(),
|
lastUpdatedAt: __t.timestamp(),
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import { type Infer as __Infer } from "spacetimedb";
|
|||||||
import PauseReducer from "../pause_reducer";
|
import PauseReducer from "../pause_reducer";
|
||||||
import PlayReducer from "../play_reducer";
|
import PlayReducer from "../play_reducer";
|
||||||
import SeekReducer from "../seek_reducer";
|
import SeekReducer from "../seek_reducer";
|
||||||
|
import SetSubtitleUrlReducer from "../set_subtitle_url_reducer";
|
||||||
import SetUrlReducer from "../set_url_reducer";
|
import SetUrlReducer from "../set_url_reducer";
|
||||||
|
|
||||||
export type PauseParams = __Infer<typeof PauseReducer>;
|
export type PauseParams = __Infer<typeof PauseReducer>;
|
||||||
export type PlayParams = __Infer<typeof PlayReducer>;
|
export type PlayParams = __Infer<typeof PlayReducer>;
|
||||||
export type SeekParams = __Infer<typeof SeekReducer>;
|
export type SeekParams = __Infer<typeof SeekReducer>;
|
||||||
|
export type SetSubtitleUrlParams = __Infer<typeof SetSubtitleUrlReducer>;
|
||||||
export type SetUrlParams = __Infer<typeof SetUrlReducer>;
|
export type SetUrlParams = __Infer<typeof SetUrlReducer>;
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
export default __t.row({
|
export default __t.row({
|
||||||
id: __t.u64().primaryKey(),
|
id: __t.u64().primaryKey(),
|
||||||
url: __t.string(),
|
url: __t.string(),
|
||||||
|
subtitleUrl: __t.string().name("subtitle_url"),
|
||||||
timePosition: __t.f64().name("time_position"),
|
timePosition: __t.f64().name("time_position"),
|
||||||
isPlaying: __t.bool().name("is_playing"),
|
isPlaying: __t.bool().name("is_playing"),
|
||||||
lastUpdatedAt: __t.timestamp().name("last_updated_at"),
|
lastUpdatedAt: __t.timestamp().name("last_updated_at"),
|
||||||
|
|||||||
+99
-4
@@ -1,6 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { useSpacetimeDB, useTable, useReducer } from "spacetimedb/svelte";
|
import { useSpacetimeDB, useTable, useReducer } from "spacetimedb/svelte";
|
||||||
import { tables, reducers } from "$lib/st-bindings";
|
import { tables, reducers } from "$lib/st-bindings";
|
||||||
|
import JASSUB from "jassub";
|
||||||
|
import font1 from "$lib/assets/fonts/trebuc_0.ttf";
|
||||||
|
|
||||||
const conn = useSpacetimeDB();
|
const conn = useSpacetimeDB();
|
||||||
|
|
||||||
@@ -8,15 +10,36 @@
|
|||||||
const videoState = $derived($videoStates.find((state) => state.id === 1n));
|
const videoState = $derived($videoStates.find((state) => state.id === 1n));
|
||||||
|
|
||||||
const setUrlReducer = useReducer(reducers.setUrl);
|
const setUrlReducer = useReducer(reducers.setUrl);
|
||||||
|
const setSubtitleUrlReducer = useReducer(reducers.setSubtitleUrl);
|
||||||
const playReducer = useReducer(reducers.play);
|
const playReducer = useReducer(reducers.play);
|
||||||
const pauseReducer = useReducer(reducers.pause);
|
const pauseReducer = useReducer(reducers.pause);
|
||||||
const seekReducer = useReducer(reducers.seek);
|
const seekReducer = useReducer(reducers.seek);
|
||||||
|
|
||||||
let videoElement: HTMLVideoElement | undefined = $state();
|
let videoElement: HTMLVideoElement | undefined = $state();
|
||||||
|
let containerElement: HTMLDivElement | undefined = $state();
|
||||||
let newUrl = $state("");
|
let newUrl = $state("");
|
||||||
|
let newSubtitleUrl = $state("");
|
||||||
|
|
||||||
let isSyncing = false;
|
let isSyncing = false;
|
||||||
let syncTimeout: ReturnType<typeof setTimeout> | undefined;
|
let syncTimeout: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
let jassubInstance: any | undefined;
|
||||||
|
let currentSubtitleUrl = $derived(videoState?.subtitleUrl);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
console.log("effect-1");
|
||||||
|
if (videoElement && currentSubtitleUrl && currentSubtitleUrl.endsWith(".ass")) {
|
||||||
|
jassubInstance = new JASSUB({
|
||||||
|
video: videoElement,
|
||||||
|
subUrl: currentSubtitleUrl,
|
||||||
|
fonts: [font1],
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
jassubInstance?.destroy();
|
||||||
|
jassubInstance = undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function syncAction(fn: () => void) {
|
function syncAction(fn: () => void) {
|
||||||
isSyncing = true;
|
isSyncing = true;
|
||||||
@@ -28,6 +51,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
console.log("effect-2");
|
||||||
if (!videoElement || !videoState) return;
|
if (!videoElement || !videoState) return;
|
||||||
const el = videoElement;
|
const el = videoElement;
|
||||||
const state = videoState;
|
const state = videoState;
|
||||||
@@ -45,8 +69,9 @@
|
|||||||
const diff = Math.abs(el.currentTime - expectedTime);
|
const diff = Math.abs(el.currentTime - expectedTime);
|
||||||
|
|
||||||
if (!state.isPlaying) {
|
if (!state.isPlaying) {
|
||||||
if (el.currentTime < expectedTime && diff <= 2 && !el.paused) {
|
if (el.currentTime < expectedTime && diff <= 2) {
|
||||||
// Behind pause point. Keep playing to catch up. (timeupdate will pause it)
|
// Behind pause point. Keep playing to catch up. (timeupdate will pause it)
|
||||||
|
// If locally paused, stay paused (we likely dispatched the pause event + buffer)
|
||||||
} else {
|
} else {
|
||||||
// Ahead or reached pause point. Pause and rewind if needed.
|
// Ahead or reached pause point. Pause and rewind if needed.
|
||||||
syncAction(() => {
|
syncAction(() => {
|
||||||
@@ -72,12 +97,14 @@
|
|||||||
|
|
||||||
function handlePlay() {
|
function handlePlay() {
|
||||||
if (isSyncing) return;
|
if (isSyncing) return;
|
||||||
playReducer({ timePosition: videoElement?.currentTime ?? 0 });
|
// Send play slightly in future to adjust for network latency
|
||||||
|
playReducer({ timePosition: (videoElement?.currentTime ?? 0) + 0.15 });
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePause() {
|
function handlePause() {
|
||||||
if (isSyncing) return;
|
if (isSyncing) return;
|
||||||
pauseReducer({ timePosition: videoElement?.currentTime ?? 0 });
|
// Send pause slightly in future, so remote clients coast into it
|
||||||
|
pauseReducer({ timePosition: (videoElement?.currentTime ?? 0) + 0.15 });
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSeeked() {
|
function handleSeeked() {
|
||||||
@@ -108,6 +135,21 @@
|
|||||||
setUrlReducer({ url: newUrl });
|
setUrlReducer({ url: newUrl });
|
||||||
newUrl = "";
|
newUrl = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSetSubtitle(e: SubmitEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!newSubtitleUrl.trim() || !$conn.isActive) return;
|
||||||
|
setSubtitleUrlReducer({ url: newSubtitleUrl });
|
||||||
|
newSubtitleUrl = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleFullscreen() {
|
||||||
|
if (!document.fullscreenElement) {
|
||||||
|
containerElement?.requestFullscreen().catch(console.error);
|
||||||
|
} else {
|
||||||
|
document.exitFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
@@ -131,18 +173,71 @@
|
|||||||
<button type="submit" class="p-2" disabled={!$conn.isActive}>Set URL</button>
|
<button type="submit" class="p-2" disabled={!$conn.isActive}>Set URL</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<form onsubmit={handleSetSubtitle} class="mb-2">
|
||||||
|
<input
|
||||||
|
type="url"
|
||||||
|
placeholder="Enter subtitle track URL (.vtt/.ass)"
|
||||||
|
bind:value={newSubtitleUrl}
|
||||||
|
class="mr-2 w-96 p-2"
|
||||||
|
/>
|
||||||
|
<button type="submit" class="p-2">Set Subtitles</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
<div
|
||||||
|
bind:this={containerElement}
|
||||||
|
class="fullscreen-container relative w-full max-w-2xl bg-black"
|
||||||
|
>
|
||||||
<!-- svelte-ignore a11y_media_has_caption -->
|
<!-- svelte-ignore a11y_media_has_caption -->
|
||||||
<video
|
<video
|
||||||
bind:this={videoElement}
|
bind:this={videoElement}
|
||||||
|
muted
|
||||||
controls
|
controls
|
||||||
|
controlslist="nofullscreen"
|
||||||
|
crossorigin="anonymous"
|
||||||
onplay={handlePlay}
|
onplay={handlePlay}
|
||||||
onpause={handlePause}
|
onpause={handlePause}
|
||||||
onseeked={handleSeeked}
|
onseeked={handleSeeked}
|
||||||
ontimeupdate={handleTimeUpdate}
|
ontimeupdate={handleTimeUpdate}
|
||||||
class="w-full max-w-2xl bg-black"
|
ondblclick={toggleFullscreen}
|
||||||
|
class="h-full w-full"
|
||||||
>
|
>
|
||||||
|
{#if videoState?.subtitleUrl && !videoState.subtitleUrl.endsWith(".ass")}
|
||||||
|
<track
|
||||||
|
src={videoState.subtitleUrl}
|
||||||
|
kind="subtitles"
|
||||||
|
srclang="en"
|
||||||
|
label="English"
|
||||||
|
default
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
Your browser does not support the video tag.
|
Your browser does not support the video tag.
|
||||||
</video>
|
</video>
|
||||||
|
<button
|
||||||
|
onclick={toggleFullscreen}
|
||||||
|
class="absolute top-2 right-2 z-50 rounded bg-black/70 px-2 py-1 text-xs text-white opacity-50 transition-opacity hover:opacity-100"
|
||||||
|
>
|
||||||
|
Fullscreen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:global(.JASSUB) {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
:global(.fullscreen-container:fullscreen) {
|
||||||
|
max-width: none !important;
|
||||||
|
width: 100vw !important;
|
||||||
|
height: 100vh !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
:global(.fullscreen-container:fullscreen video) {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
+9
-1
@@ -3,4 +3,12 @@ import tailwindcss from "@tailwindcss/vite";
|
|||||||
import { sveltekit } from "@sveltejs/kit/vite";
|
import { sveltekit } from "@sveltejs/kit/vite";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
export default defineConfig({ plugins: [tailwindcss(), sveltekit(), devtoolsJson()] });
|
export default defineConfig({
|
||||||
|
plugins: [tailwindcss(), sveltekit(), devtoolsJson()],
|
||||||
|
optimizeDeps: {
|
||||||
|
// for some reason this specific combination of
|
||||||
|
// includes/excludes is required for jassub to work
|
||||||
|
exclude: ["jassub"],
|
||||||
|
include: ["throughput"],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user