Compare commits
1 Commits
master
...
f7636f61a7
| Author | SHA1 | Date | |
|---|---|---|---|
|
f7636f61a7
|
@@ -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,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -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),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
15
src/lib/st-bindings/set_subtitle_url_reducer.ts
Normal file
15
src/lib/st-bindings/set_subtitle_url_reducer.ts
Normal 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(),
|
||||||
|
};
|
||||||
@@ -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"),
|
||||||
|
|||||||
@@ -8,12 +8,14 @@
|
|||||||
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 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;
|
||||||
@@ -111,6 +113,13 @@
|
|||||||
setUrlReducer({ url: newUrl });
|
setUrlReducer({ url: newUrl });
|
||||||
newUrl = "";
|
newUrl = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSetSubtitle(e: SubmitEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!newSubtitleUrl.trim() || !$conn.isActive) return;
|
||||||
|
setSubtitleUrlReducer({ url: newSubtitleUrl });
|
||||||
|
newSubtitleUrl = "";
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
@@ -134,18 +143,32 @@
|
|||||||
<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)"
|
||||||
|
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 -->
|
<!-- svelte-ignore a11y_media_has_caption -->
|
||||||
<video
|
<video
|
||||||
bind:this={videoElement}
|
bind:this={videoElement}
|
||||||
muted
|
muted
|
||||||
controls
|
controls
|
||||||
|
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"
|
class="w-full max-w-2xl bg-black"
|
||||||
>
|
>
|
||||||
|
{#if videoState?.subtitleUrl}
|
||||||
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user