mirror of
https://github.com/gradio-app/gradio.git
synced 2024-11-27 01:40:20 +08:00
add new audio + video events (#4422)
This commit is contained in:
parent
9c5a1d871c
commit
fd2538bd05
@ -2,7 +2,7 @@
|
||||
|
||||
## New Features:
|
||||
|
||||
No changes to highlight.
|
||||
- Add `start_recording` and `stop_recording` events to `Video` and `Audio` components by [@pngwn](https://github.com/pngwn) in [PR 4422](https://github.com/gradio-app/gradio/pull/4422)
|
||||
|
||||
## Bug Fixes:
|
||||
|
||||
|
@ -64,6 +64,7 @@ from gradio.events import (
|
||||
EventListenerMethod,
|
||||
Inputable,
|
||||
Playable,
|
||||
Recordable,
|
||||
Releaseable,
|
||||
Selectable,
|
||||
Streamable,
|
||||
@ -2134,6 +2135,7 @@ class Video(
|
||||
Changeable,
|
||||
Clearable,
|
||||
Playable,
|
||||
Recordable,
|
||||
Uploadable,
|
||||
IOComponent,
|
||||
VideoSerializable,
|
||||
@ -2482,6 +2484,7 @@ class Audio(
|
||||
Changeable,
|
||||
Clearable,
|
||||
Playable,
|
||||
Recordable,
|
||||
Streamable,
|
||||
Uploadable,
|
||||
IOComponent,
|
||||
|
@ -131,6 +131,11 @@ class EventListenerMethod:
|
||||
warnings.warn(
|
||||
"The 'status_tracker' parameter has been deprecated and has no effect."
|
||||
)
|
||||
if self.event_name == "stop":
|
||||
warnings.warn(
|
||||
"The `stop` event on Video and Audio has been deprecated and will be remove in a future version. Use `ended` instead."
|
||||
)
|
||||
|
||||
if isinstance(self, Streamable):
|
||||
self.check_streamable()
|
||||
if isinstance(show_progress, bool):
|
||||
@ -234,13 +239,19 @@ class Playable(EventListener):
|
||||
|
||||
self.pause = EventListenerMethod(self, "pause")
|
||||
"""
|
||||
This listener is triggered when the user pauses the component (e.g. audio or video).
|
||||
This listener is triggered when the media stops playing for any reason (e.g. audio or video).
|
||||
This method can be used when this component is in a Gradio Blocks.
|
||||
"""
|
||||
|
||||
self.stop = EventListenerMethod(self, "stop")
|
||||
"""
|
||||
This listener is triggered when the user stops the component (e.g. audio or video).
|
||||
This listener is triggered when the user reaches the end of the media track (e.g. audio or video).
|
||||
This method can be used when this component is in a Gradio Blocks.
|
||||
"""
|
||||
|
||||
self.end = EventListenerMethod(self, "end")
|
||||
"""
|
||||
This listener is triggered when the user reaches the end of the media track (e.g. audio or video).
|
||||
This method can be used when this component is in a Gradio Blocks.
|
||||
"""
|
||||
|
||||
@ -264,6 +275,22 @@ class Streamable(EventListener):
|
||||
pass
|
||||
|
||||
|
||||
@document("*start_recording", "*stop_recording", inherit=True)
|
||||
class Recordable(EventListener):
|
||||
def __init__(self):
|
||||
self.start_recording = EventListenerMethod(self, "start_recording")
|
||||
"""
|
||||
This listener is triggered when the user starts recording with the component (e.g. audio or video).
|
||||
This method can be used when this component is in a Gradio Blocks.
|
||||
"""
|
||||
|
||||
self.stop_recording = EventListenerMethod(self, "stop_recording")
|
||||
"""
|
||||
This listener is triggered when the user stops recording with the component (e.g. audio or video).
|
||||
This method can be used when this component is in a Gradio Blocks.
|
||||
"""
|
||||
|
||||
|
||||
@document("*blur", inherit=True)
|
||||
class Blurrable(EventListener):
|
||||
def __init__(self):
|
||||
|
@ -78,7 +78,10 @@
|
||||
on:edit
|
||||
on:play
|
||||
on:pause
|
||||
on:ended
|
||||
on:stop
|
||||
on:end
|
||||
on:start_recording
|
||||
on:stop_recording
|
||||
on:upload
|
||||
on:error={({ detail }) => {
|
||||
loading_status = loading_status || {};
|
||||
|
@ -93,6 +93,7 @@
|
||||
{show_label}
|
||||
on:play
|
||||
on:pause
|
||||
on:stop
|
||||
/>
|
||||
{:else}
|
||||
<Video
|
||||
@ -114,6 +115,10 @@
|
||||
on:play
|
||||
on:pause
|
||||
on:upload
|
||||
on:stop
|
||||
on:end
|
||||
on:start_recording
|
||||
on:stop_recording
|
||||
>
|
||||
<UploadText type="video" />
|
||||
</Video>
|
||||
|
@ -64,11 +64,14 @@
|
||||
edit: AudioData;
|
||||
play: undefined;
|
||||
pause: undefined;
|
||||
ended: undefined;
|
||||
stop: undefined;
|
||||
end: undefined;
|
||||
drag: boolean;
|
||||
error: string;
|
||||
upload: FileData;
|
||||
clear: undefined;
|
||||
start_recording: undefined;
|
||||
stop_recording: undefined;
|
||||
}>();
|
||||
|
||||
function blob_to_data_url(blob: Blob): Promise<string> {
|
||||
@ -164,7 +167,7 @@
|
||||
|
||||
async function record() {
|
||||
recording = true;
|
||||
|
||||
dispatch("start_recording");
|
||||
if (!inited) await prepare_audio();
|
||||
header = undefined;
|
||||
if (streaming) {
|
||||
@ -181,6 +184,7 @@
|
||||
});
|
||||
|
||||
const stop = async () => {
|
||||
dispatch("stop_recording");
|
||||
recorder.stop();
|
||||
if (streaming) {
|
||||
recording = false;
|
||||
@ -250,6 +254,11 @@
|
||||
dispatch("upload", detail);
|
||||
}
|
||||
|
||||
function handle_ended() {
|
||||
dispatch("stop");
|
||||
dispatch("end");
|
||||
}
|
||||
|
||||
export let dragging = false;
|
||||
$: dispatch("drag", dragging);
|
||||
</script>
|
||||
@ -306,7 +315,7 @@
|
||||
src={value.data}
|
||||
on:play
|
||||
on:pause
|
||||
on:ended
|
||||
on:ended={handle_ended}
|
||||
/>
|
||||
|
||||
{#if mode === "edit" && player?.duration}
|
||||
|
@ -22,7 +22,8 @@
|
||||
change: AudioData;
|
||||
play: undefined;
|
||||
pause: undefined;
|
||||
ended: undefined;
|
||||
end: undefined;
|
||||
stop: undefined;
|
||||
}>();
|
||||
|
||||
$: value &&
|
||||
@ -30,6 +31,11 @@
|
||||
name: name,
|
||||
data: value?.data
|
||||
});
|
||||
|
||||
function handle_ended() {
|
||||
dispatch("stop");
|
||||
dispatch("end");
|
||||
}
|
||||
</script>
|
||||
|
||||
<BlockLabel {show_label} Icon={Music} float={false} label={label || "Audio"} />
|
||||
@ -44,7 +50,7 @@
|
||||
src={value.data}
|
||||
on:play
|
||||
on:pause
|
||||
on:ended
|
||||
on:ended={handle_ended}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onMount } from "svelte";
|
||||
import { Camera, Circle, Square } from "@gradio/icons";
|
||||
import type { FileData } from "@gradio/upload";
|
||||
|
||||
let video_source: HTMLVideoElement;
|
||||
let canvas: HTMLCanvasElement;
|
||||
@ -11,7 +12,19 @@
|
||||
export let mirror_webcam: boolean;
|
||||
export let include_audio: boolean;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
stream: undefined;
|
||||
capture:
|
||||
| {
|
||||
data: FileReader["result"];
|
||||
name: string;
|
||||
is_example?: boolean;
|
||||
}
|
||||
| string;
|
||||
error: string;
|
||||
start_recording: undefined;
|
||||
stop_recording: undefined;
|
||||
}>();
|
||||
|
||||
onMount(() => (canvas = document.createElement("canvas")));
|
||||
|
||||
@ -61,6 +74,7 @@
|
||||
|
||||
function take_recording() {
|
||||
if (recording) {
|
||||
dispatch("stop_recording");
|
||||
media_recorder.stop();
|
||||
let video_blob = new Blob(recorded_blobs, { type: mimeType });
|
||||
let ReaderObj = new FileReader();
|
||||
@ -75,6 +89,7 @@
|
||||
};
|
||||
ReaderObj.readAsDataURL(video_blob);
|
||||
} else {
|
||||
dispatch("start_recording");
|
||||
recorded_blobs = [];
|
||||
let validMimeTypes = ["video/webm", "video/mp4"];
|
||||
for (let validMimeType of validMimeTypes) {
|
||||
|
@ -1,10 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { tick, createEventDispatcher } from "svelte";
|
||||
import { Play, Pause, Maximise, Undo } from "@gradio/icons";
|
||||
|
||||
export let src: string;
|
||||
export let subtitle: string | null = null;
|
||||
export let mirror: boolean;
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
play: undefined;
|
||||
pause: undefined;
|
||||
stop: undefined;
|
||||
end: undefined;
|
||||
}>();
|
||||
|
||||
let time: number = 0;
|
||||
let duration: number;
|
||||
let paused: boolean = true;
|
||||
@ -69,6 +77,44 @@
|
||||
|
||||
return `${minutes}:${_seconds}`;
|
||||
}
|
||||
|
||||
async function checkforVideo() {
|
||||
transition = "0s";
|
||||
await tick();
|
||||
wrap_opacity = 0.8;
|
||||
opacity = 0;
|
||||
await tick();
|
||||
|
||||
var b = setInterval(async () => {
|
||||
if (video.readyState >= 3) {
|
||||
video.currentTime = 9999;
|
||||
paused = true;
|
||||
transition = "0.2s";
|
||||
|
||||
setTimeout(async () => {
|
||||
video.currentTime = 0.0;
|
||||
opacity = 1;
|
||||
wrap_opacity = 1;
|
||||
}, 50);
|
||||
clearInterval(b);
|
||||
}
|
||||
}, 15);
|
||||
}
|
||||
|
||||
async function _load() {
|
||||
checkforVideo();
|
||||
}
|
||||
|
||||
let opacity: number = 0;
|
||||
let wrap_opacity: number = 0;
|
||||
let transition: string = "0.5s";
|
||||
|
||||
$: src && _load();
|
||||
|
||||
function handle_end() {
|
||||
dispatch("stop");
|
||||
dispatch("end");
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="wrap">
|
||||
@ -79,7 +125,7 @@
|
||||
on:click={play_pause}
|
||||
on:play
|
||||
on:pause
|
||||
on:ended
|
||||
on:ended={handle_end}
|
||||
bind:currentTime={time}
|
||||
bind:duration
|
||||
bind:paused
|
||||
|
@ -1,10 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
createEventDispatcher,
|
||||
afterUpdate,
|
||||
tick,
|
||||
beforeUpdate
|
||||
} from "svelte";
|
||||
import { createEventDispatcher, afterUpdate, tick } from "svelte";
|
||||
import { BlockLabel, Empty, IconButton } from "@gradio/atoms";
|
||||
import type { FileData } from "@gradio/upload";
|
||||
import { Video, Download } from "@gradio/icons";
|
||||
@ -22,7 +17,8 @@
|
||||
change: FileData;
|
||||
play: undefined;
|
||||
pause: undefined;
|
||||
ended: undefined;
|
||||
end: undefined;
|
||||
stop: undefined;
|
||||
}>();
|
||||
|
||||
$: value && dispatch("change", value);
|
||||
|
@ -18,14 +18,16 @@
|
||||
export let include_audio: boolean;
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: FileData | null;
|
||||
change: any;
|
||||
clear: undefined;
|
||||
play: undefined;
|
||||
pause: undefined;
|
||||
ended: undefined;
|
||||
end: undefined;
|
||||
drag: boolean;
|
||||
error: string;
|
||||
upload: FileData;
|
||||
start_recording: undefined;
|
||||
stop_recording: undefined;
|
||||
}>();
|
||||
|
||||
function handle_load({ detail }: CustomEvent<FileData | null>) {
|
||||
@ -57,6 +59,8 @@
|
||||
mode="video"
|
||||
on:error
|
||||
on:capture={({ detail }) => dispatch("change", detail)}
|
||||
on:start_recording
|
||||
on:stop_recording
|
||||
/>
|
||||
{/if}
|
||||
{:else}
|
||||
@ -68,7 +72,8 @@
|
||||
subtitle={subtitle?.data}
|
||||
on:play
|
||||
on:pause
|
||||
on:ended
|
||||
on:stop
|
||||
on:end
|
||||
mirror={mirror_webcam && source === "webcam"}
|
||||
/>
|
||||
{:else if value.size}
|
||||
|
Loading…
Reference in New Issue
Block a user