mirror of
https://github.com/gradio-app/gradio.git
synced 2024-12-27 02:30:17 +08:00
67ddd40b4b
* Fix vite.config.js detecting the development mode * Fix the imports of @gradio/theme in js/app/src/lite/index.ts * [WIP] Install Pydantic V1 and mock the RootModel class * Remove Wasm WebSocket implementations * Move ASGI-HTTP conversion logic from the worker to the worker-proxy so we have fine controls on the ASGI connection at the worker-proxy level for the HTTP stream connection impl in the future * Fix asgi-types.ts * Create `WasmWorkerEventSource` and inject the `EventSource` creation in @gradio/client * Mock Pydantic V2's BaseModel * Fix Pydantic V1 installation * Make <ImageUploader /> and <ImagePreview /> Wasm-compatible * Create `getHeaderValue()` * Create `<DownloadLink />` for Wasm-compatible download and fix `<ImagePreview />` to use it * Make `gr.Video()` Wasm-compatible avoiding unnecessary execution of ffprobe * Move `<DownloadLink />` to @gradio/wasm and use it in `<VideoPreview />` too * Fix `<DownloadLink />` making `href` optional and adding `rel="noopener noreferrer"` * Make the download button of `<StaticAudio>` and `<Code />` Wasm-compatible * Make the download button of `<FilePreview />` Wasm-compatible * Improve the RootModel mock class for `.model_dump()` and `.model_json_schame()` to work * Make `<UploadProgress />` Wasm-compatible * Fix `WorkerProxy.httpRequest()` to use `decodeURIComponent()` to process `path` and `query_string` * Fix `<InteractiveAudio />` to make its upload feature Wasm-compatible * [WIP] Revert "Make `<UploadProgress />` Wasm-compatible" This reverts commit f96b4b7d5e92bb488cfe1939d25063366f714178. * Fix Image styles * Fix `<AudioPlayer />`'s `create_waveform()` to be Wasm-compatible * add changeset * formatting * Fix js/image/shared/Image.svelte to render <img> immediately * Fix js/image/shared/Image.svelte to avoid race condition * Fix js/image/shared/Image.svelte * Fix js/image/shared/Image.svelte * Fix js/image/shared/Image.svelte removing unnecessary styles * Fix js/video/shared/Video.svelte to use the passed immediately without waiting for the async resolution --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: aliabd <ali.si3luwa@gmail.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
144 lines
4.0 KiB
Svelte
144 lines
4.0 KiB
Svelte
<script lang="ts">
|
|
import type { HTMLVideoAttributes } from "svelte/elements";
|
|
import { createEventDispatcher } from "svelte";
|
|
import { loaded } from "./utils";
|
|
|
|
import { resolve_wasm_src } from "@gradio/wasm/svelte";
|
|
|
|
export let src: HTMLVideoAttributes["src"] = undefined;
|
|
|
|
export let muted: HTMLVideoAttributes["muted"] = undefined;
|
|
export let playsinline: HTMLVideoAttributes["playsinline"] = undefined;
|
|
export let preload: HTMLVideoAttributes["preload"] = undefined;
|
|
export let autoplay: HTMLVideoAttributes["autoplay"] = undefined;
|
|
export let controls: HTMLVideoAttributes["controls"] = undefined;
|
|
|
|
export let currentTime: number | undefined = undefined;
|
|
export let duration: number | undefined = undefined;
|
|
export let paused: boolean | undefined = undefined;
|
|
|
|
export let node: HTMLVideoElement | undefined = undefined;
|
|
|
|
export let processingVideo = false;
|
|
|
|
const dispatch = createEventDispatcher();
|
|
|
|
let resolved_src: typeof src;
|
|
|
|
// The `src` prop can be updated before the Promise from `resolve_wasm_src` is resolved.
|
|
// In such a case, the resolved value for the old `src` has to be discarded,
|
|
// This variable `latest_src` is used to pick up only the value resolved for the latest `src` prop.
|
|
let latest_src: typeof src;
|
|
$: {
|
|
// In normal (non-Wasm) Gradio, the `<img>` element should be rendered with the passed `src` props immediately
|
|
// without waiting for `resolve_wasm_src()` to resolve.
|
|
// If it waits, a black image is displayed until the async task finishes
|
|
// and it leads to undesirable flickering.
|
|
// So set `src` to `resolved_src` here.
|
|
resolved_src = src;
|
|
|
|
latest_src = src;
|
|
const resolving_src = src;
|
|
resolve_wasm_src(resolving_src).then((s) => {
|
|
if (latest_src === resolving_src) {
|
|
resolved_src = s;
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<!--
|
|
The spread operator with `$$props` or `$$restProps` can't be used here
|
|
to pass props from the parent component to the <video> element
|
|
because of its unexpected behavior: https://github.com/sveltejs/svelte/issues/7404
|
|
For example, if we add {...$$props} or {...$$restProps}, the boolean props aside it like `controls` will be compiled as string "true" or "false" on the actual DOM.
|
|
Then, even when `controls` is false, the compiled DOM would be `<video controls="false">` which is equivalent to `<video controls>` since the string "false" is even truthy.
|
|
-->
|
|
<div class:hidden={!processingVideo} class="overlay">
|
|
<span class="load-wrap">
|
|
<span class="loader" />
|
|
</span>
|
|
</div>
|
|
<video
|
|
src={resolved_src}
|
|
{muted}
|
|
{playsinline}
|
|
{preload}
|
|
{autoplay}
|
|
{controls}
|
|
on:loadeddata={dispatch.bind(null, "loadeddata")}
|
|
on:click={dispatch.bind(null, "click")}
|
|
on:play={dispatch.bind(null, "play")}
|
|
on:pause={dispatch.bind(null, "pause")}
|
|
on:ended={dispatch.bind(null, "ended")}
|
|
on:mouseover={dispatch.bind(null, "mouseover")}
|
|
on:mouseout={dispatch.bind(null, "mouseout")}
|
|
on:focus={dispatch.bind(null, "focus")}
|
|
on:blur={dispatch.bind(null, "blur")}
|
|
bind:currentTime
|
|
bind:duration
|
|
bind:paused
|
|
bind:this={node}
|
|
use:loaded={{ autoplay: autoplay ?? false }}
|
|
data-testid={$$props["data-testid"]}
|
|
crossorigin="anonymous"
|
|
>
|
|
<slot />
|
|
</video>
|
|
|
|
<style>
|
|
.overlay {
|
|
position: absolute;
|
|
background-color: rgba(0, 0, 0, 0.4);
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.hidden {
|
|
display: none;
|
|
}
|
|
|
|
.load-wrap {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100%;
|
|
}
|
|
|
|
.loader {
|
|
display: flex;
|
|
position: relative;
|
|
background-color: var(--border-color-accent-subdued);
|
|
animation: shadowPulse 2s linear infinite;
|
|
box-shadow:
|
|
-24px 0 var(--border-color-accent-subdued),
|
|
24px 0 var(--border-color-accent-subdued);
|
|
margin: var(--spacing-md);
|
|
border-radius: 50%;
|
|
width: 10px;
|
|
height: 10px;
|
|
scale: 0.5;
|
|
}
|
|
|
|
@keyframes shadowPulse {
|
|
33% {
|
|
box-shadow:
|
|
-24px 0 var(--border-color-accent-subdued),
|
|
24px 0 #fff;
|
|
background: #fff;
|
|
}
|
|
66% {
|
|
box-shadow:
|
|
-24px 0 #fff,
|
|
24px 0 #fff;
|
|
background: var(--border-color-accent-subdued);
|
|
}
|
|
100% {
|
|
box-shadow:
|
|
-24px 0 #fff,
|
|
24px 0 var(--border-color-accent-subdued);
|
|
background: #fff;
|
|
}
|
|
}
|
|
</style>
|