Compare commits

..

6 Commits

Author SHA1 Message Date
37cfb375b8 attempt fix subs fullscreen 2026-04-16 07:50:55 -07:00
ea3d92974b subs fix pause 2026-04-15 21:49:25 -07:00
0cb2a7739a some fonts 2026-04-15 21:46:06 -07:00
5d82e92461 ass subs working pt. 1 2026-04-15 21:06:52 -07:00
151c719901 ass subs attempt pt. 1 2026-04-15 20:37:12 -07:00
f7636f61a7 vtt subtitles 2026-04-15 19:08:31 -07:00
24 changed files with 162 additions and 13 deletions

View File

@@ -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/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
"abslink": ["abslink@1.1.6", "", {}, "sha512-8fQgnUoVSgc1IhOrYzdDY+wTDPktbuYjds2LKf9kWYWKwDnHgXU168gdV3sPei7vevFf5m2fPZ6IQSKZkSjHVg=="],
"acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
"aria-query": ["aria-query@5.3.1", "", {}, "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g=="], "aria-query": ["aria-query@5.3.1", "", {}, "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g=="],
@@ -314,10 +319,14 @@
"is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
"jassub": ["jassub@2.4.2", "", { "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": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
"lfa-ponyfill": ["lfa-ponyfill@1.1.0", "", {}, "sha512-YS3/DmyDdywWwoEu1ZacAudqkJ4q7WtKE9+bWlaSuEoVrXva7ChIJHMJYs19zyVc1H198pzqAreQU0r/+YNeew=="],
"lightningcss": ["lightningcss@1.32.0", "", { "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": ["lightningcss@1.32.0", "", { "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": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
@@ -382,6 +391,8 @@
"rollup": ["rollup@4.60.1", "", { "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": ["rollup@4.60.1", "", { "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": ["rvfc-polyfill@1.0.8", "", {}, "sha512-uA+0wwTkZ4OT8v45pfDfH+7Yq8mY6MvNngiF5Sq6VBgjJsvsfgt7Q18cyZqZjfAhW9rhkgXPX0cW0R9uw7yElA=="],
"sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
@@ -410,6 +421,8 @@
"tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="],
"throughput": ["throughput@1.0.2", "", {}, "sha512-jvK1ZXuhsggjb3qYQjMiU/AVYYiTeqT5thWvYR2yuy2LGM84P5MSSyAinwHahGsdBYKR9m9HncVR/3f3nFKkxg=="],
"tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
"totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],

View File

@@ -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"
} }
} }

View File

@@ -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.

View File

@@ -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),
); );

View File

@@ -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(),
};

View File

@@ -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(),

View File

@@ -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>;

View File

@@ -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"),

View File

@@ -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;
@@ -111,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">
@@ -134,19 +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>
<!-- svelte-ignore a11y_media_has_caption --> <div
<video bind:this={containerElement}
bind:this={videoElement} class="fullscreen-container relative w-full max-w-2xl bg-black"
muted
controls
onplay={handlePlay}
onpause={handlePause}
onseeked={handleSeeked}
ontimeupdate={handleTimeUpdate}
class="w-full max-w-2xl bg-black"
> >
Your browser does not support the video tag. <!-- svelte-ignore a11y_media_has_caption -->
</video> <video
bind:this={videoElement}
muted
controls
controlslist="nofullscreen"
crossorigin="anonymous"
onplay={handlePlay}
onpause={handlePause}
onseeked={handleSeeked}
ontimeupdate={handleTimeUpdate}
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.
</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>

View File

@@ -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"],
}
});