@gradio/video 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/Example.svelte +21 -19
- package/Index.svelte +3 -4
- package/Video.stories.svelte +16 -4
- package/Video.test.ts +36 -22
- package/package.json +8 -8
- package/shared/Player.svelte +2 -11
- package/shared/VideoControls.svelte +2 -13
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# @gradio/video
|
2
2
|
|
3
|
+
## 0.6.0
|
4
|
+
|
5
|
+
### Features
|
6
|
+
|
7
|
+
- [#7183](https://github.com/gradio-app/gradio/pull/7183) [`49d9c48`](https://github.com/gradio-app/gradio/commit/49d9c48537aa706bf72628e3640389470138bdc6) - [WIP] Refactor file normalization to be in the backend and remove it from the frontend of each component. Thanks [@abidlabs](https://github.com/abidlabs)!
|
8
|
+
|
9
|
+
## 0.5.1
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
- [#7274](https://github.com/gradio-app/gradio/pull/7274) [`fdd1521`](https://github.com/gradio-app/gradio/commit/fdd15213c24b9cbc58bbc1b6beb4af7c18f48557) - chore: Change time format (thanks @jjshoots for the independent contribution). Thanks [@arian81](https://github.com/arian81)!
|
14
|
+
|
15
|
+
### Fixes
|
16
|
+
|
17
|
+
- [#7192](https://github.com/gradio-app/gradio/pull/7192) [`8dd6f4b`](https://github.com/gradio-app/gradio/commit/8dd6f4bc1901792f05cd59e86df7b1dbab692739) - Handle the case where examples is `null` for all components. Thanks [@abidlabs](https://github.com/abidlabs)!
|
18
|
+
|
3
19
|
## 0.5.0
|
4
20
|
|
5
21
|
### Features
|
package/Example.svelte
CHANGED
@@ -20,25 +20,27 @@
|
|
20
20
|
}
|
21
21
|
</script>
|
22
22
|
|
23
|
-
{#if
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
23
|
+
{#if value}
|
24
|
+
{#if playable()}
|
25
|
+
<div
|
26
|
+
class="container"
|
27
|
+
class:table={type === "table"}
|
28
|
+
class:gallery={type === "gallery"}
|
29
|
+
class:selected
|
30
|
+
>
|
31
|
+
<Video
|
32
|
+
muted
|
33
|
+
playsinline
|
34
|
+
bind:node={video}
|
35
|
+
on:loadeddata={init}
|
36
|
+
on:mouseover={video.play.bind(video)}
|
37
|
+
on:mouseout={video.pause.bind(video)}
|
38
|
+
src={samples_dir + value?.video.path}
|
39
|
+
/>
|
40
|
+
</div>
|
41
|
+
{:else}
|
42
|
+
<div>{value}</div>
|
43
|
+
{/if}
|
42
44
|
{/if}
|
43
45
|
|
44
46
|
<style>
|
package/Index.svelte
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
<script lang="ts">
|
4
4
|
import type { Gradio, ShareData } from "@gradio/utils";
|
5
5
|
|
6
|
-
import {
|
6
|
+
import type { FileData } from "@gradio/client";
|
7
7
|
import { Block, UploadText } from "@gradio/atoms";
|
8
8
|
import StaticVideo from "./shared/VideoPreview.svelte";
|
9
9
|
import Video from "./shared/InteractiveVideo.svelte";
|
@@ -24,7 +24,6 @@
|
|
24
24
|
| ["webcam", "upload"]
|
25
25
|
| ["upload", "webcam"];
|
26
26
|
export let root: string;
|
27
|
-
export let proxy_url: null | string;
|
28
27
|
export let show_label: boolean;
|
29
28
|
export let loading_status: LoadingStatus;
|
30
29
|
export let height: number | undefined;
|
@@ -80,8 +79,8 @@
|
|
80
79
|
|
81
80
|
$: {
|
82
81
|
if (value != null) {
|
83
|
-
_video =
|
84
|
-
_subtitle =
|
82
|
+
_video = value.video;
|
83
|
+
_subtitle = value.subtitles;
|
85
84
|
} else {
|
86
85
|
_video = null;
|
87
86
|
_subtitle = null;
|
package/Video.stories.svelte
CHANGED
@@ -1,12 +1,24 @@
|
|
1
|
-
<script>
|
2
|
-
import {
|
1
|
+
<script context="module">
|
2
|
+
import { Template, Story } from "@storybook/addon-svelte-csf";
|
3
3
|
import Video from "./Index.svelte";
|
4
4
|
import { format } from "svelte-i18n";
|
5
5
|
import { get } from "svelte/store";
|
6
6
|
import { userEvent, within } from "@storybook/testing-library";
|
7
|
-
|
7
|
+
import { allModes } from "../storybook/modes";
|
8
8
|
|
9
|
-
|
9
|
+
export const meta = {
|
10
|
+
title: "Components/Video",
|
11
|
+
component: Video,
|
12
|
+
parameters: {
|
13
|
+
chromatic: {
|
14
|
+
modes: {
|
15
|
+
desktop: allModes["desktop"],
|
16
|
+
mobile: allModes["mobile"]
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
};
|
21
|
+
</script>
|
10
22
|
|
11
23
|
<div>
|
12
24
|
<Template let:args>
|
package/Video.test.ts
CHANGED
@@ -41,8 +41,10 @@ describe("Video", () => {
|
|
41
41
|
loading_status,
|
42
42
|
value: {
|
43
43
|
video: {
|
44
|
-
path: "https://
|
45
|
-
|
44
|
+
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
45
|
+
url: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
46
|
+
},
|
47
|
+
subtitles: null
|
46
48
|
},
|
47
49
|
label: "Test Label",
|
48
50
|
root: "foo",
|
@@ -56,7 +58,7 @@ describe("Video", () => {
|
|
56
58
|
let vid = getByTestId("Test Label-player") as HTMLVideoElement;
|
57
59
|
assert.equal(
|
58
60
|
vid.src,
|
59
|
-
"https://
|
61
|
+
"https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
60
62
|
);
|
61
63
|
assert.equal(queryAllByText("Test Label").length, 1);
|
62
64
|
});
|
@@ -67,8 +69,10 @@ describe("Video", () => {
|
|
67
69
|
loading_status,
|
68
70
|
value: {
|
69
71
|
video: {
|
70
|
-
path: "https://
|
71
|
-
|
72
|
+
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
73
|
+
url: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
74
|
+
},
|
75
|
+
subtitles: null
|
72
76
|
},
|
73
77
|
label: "Video Component",
|
74
78
|
root: "foo",
|
@@ -88,8 +92,10 @@ describe("Video", () => {
|
|
88
92
|
loading_status,
|
89
93
|
value: {
|
90
94
|
video: {
|
91
|
-
path: "https://
|
92
|
-
|
95
|
+
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
96
|
+
url: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
97
|
+
},
|
98
|
+
subtitles: null
|
93
99
|
},
|
94
100
|
root: "foo",
|
95
101
|
proxy_url: null,
|
@@ -102,7 +108,7 @@ describe("Video", () => {
|
|
102
108
|
let vid = getByTestId("test-player") as HTMLVideoElement;
|
103
109
|
assert.equal(
|
104
110
|
vid.src,
|
105
|
-
"https://
|
111
|
+
"https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
106
112
|
);
|
107
113
|
});
|
108
114
|
|
@@ -113,8 +119,10 @@ describe("Video", () => {
|
|
113
119
|
interactive: false,
|
114
120
|
value: {
|
115
121
|
video: {
|
116
|
-
path: "https://
|
117
|
-
|
122
|
+
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
123
|
+
url: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
124
|
+
},
|
125
|
+
subtitles: null
|
118
126
|
},
|
119
127
|
root: "foo",
|
120
128
|
proxy_url: null,
|
@@ -135,8 +143,10 @@ describe("Video", () => {
|
|
135
143
|
loading_status,
|
136
144
|
value: {
|
137
145
|
video: {
|
138
|
-
path: "https://
|
139
|
-
|
146
|
+
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
147
|
+
url: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
148
|
+
},
|
149
|
+
subtitles: null
|
140
150
|
},
|
141
151
|
root: "foo",
|
142
152
|
proxy_url: null,
|
@@ -158,8 +168,10 @@ describe("Video", () => {
|
|
158
168
|
interactive: false,
|
159
169
|
value: {
|
160
170
|
video: {
|
161
|
-
path: "https://
|
162
|
-
|
171
|
+
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
172
|
+
url: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
173
|
+
},
|
174
|
+
subtitles: null
|
163
175
|
},
|
164
176
|
root: "foo",
|
165
177
|
proxy_url: null,
|
@@ -189,8 +201,10 @@ describe("Video", () => {
|
|
189
201
|
interactive: true,
|
190
202
|
value: {
|
191
203
|
video: {
|
192
|
-
path: "https://
|
193
|
-
|
204
|
+
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
205
|
+
url: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
206
|
+
},
|
207
|
+
subtitles: null
|
194
208
|
},
|
195
209
|
root: "foo",
|
196
210
|
proxy_url: null,
|
@@ -205,8 +219,10 @@ describe("Video", () => {
|
|
205
219
|
component.$set({
|
206
220
|
value: {
|
207
221
|
video: {
|
208
|
-
path: "https://
|
209
|
-
|
222
|
+
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
223
|
+
url: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
224
|
+
},
|
225
|
+
subtitles: null
|
210
226
|
}
|
211
227
|
});
|
212
228
|
startButton.dispatchEvent(new Event("loadeddata"));
|
@@ -215,10 +231,8 @@ describe("Video", () => {
|
|
215
231
|
test("renders video and download button", async () => {
|
216
232
|
const data = {
|
217
233
|
video: {
|
218
|
-
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
219
|
-
|
220
|
-
subtitles: {
|
221
|
-
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
234
|
+
path: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
235
|
+
url: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4"
|
222
236
|
}
|
223
237
|
};
|
224
238
|
const results = await render(Video, {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@gradio/video",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.6.0",
|
4
4
|
"description": "Gradio UI packages",
|
5
5
|
"type": "module",
|
6
6
|
"author": "",
|
@@ -10,14 +10,14 @@
|
|
10
10
|
"@ffmpeg/ffmpeg": "^0.12.7",
|
11
11
|
"@ffmpeg/util": "^0.12.1",
|
12
12
|
"mrmime": "^2.0.0",
|
13
|
-
"@gradio/atoms": "^0.5.
|
14
|
-
"@gradio/client": "^0.
|
13
|
+
"@gradio/atoms": "^0.5.1",
|
14
|
+
"@gradio/client": "^0.12.0",
|
15
15
|
"@gradio/icons": "^0.3.2",
|
16
|
-
"@gradio/
|
17
|
-
"@gradio/
|
18
|
-
"@gradio/
|
19
|
-
"@gradio/
|
20
|
-
"@gradio/
|
16
|
+
"@gradio/statustracker": "^0.4.5",
|
17
|
+
"@gradio/image": "^0.9.0",
|
18
|
+
"@gradio/upload": "^0.7.2",
|
19
|
+
"@gradio/utils": "^0.2.2",
|
20
|
+
"@gradio/wasm": "^0.6.0"
|
21
21
|
},
|
22
22
|
"exports": {
|
23
23
|
".": "./index.ts",
|
package/shared/Player.svelte
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
import VideoControls from "./VideoControls.svelte";
|
6
6
|
import type { FileData } from "@gradio/client";
|
7
7
|
import { prepare_files, upload } from "@gradio/client";
|
8
|
+
import { format_time } from "@gradio/utils";
|
8
9
|
|
9
10
|
export let root = "";
|
10
11
|
export let src: string;
|
@@ -70,16 +71,6 @@
|
|
70
71
|
time = (duration * (e.clientX - left)) / (right - left);
|
71
72
|
}
|
72
73
|
|
73
|
-
function format(seconds: number): string {
|
74
|
-
if (isNaN(seconds) || !isFinite(seconds)) return "...";
|
75
|
-
|
76
|
-
const minutes = Math.floor(seconds / 60);
|
77
|
-
let _seconds: number | string = Math.floor(seconds % 60);
|
78
|
-
if (_seconds < 10) _seconds = `0${_seconds}`;
|
79
|
-
|
80
|
-
return `${minutes}:${_seconds}`;
|
81
|
-
}
|
82
|
-
|
83
74
|
function handle_end(): void {
|
84
75
|
dispatch("stop");
|
85
76
|
dispatch("end");
|
@@ -138,7 +129,7 @@
|
|
138
129
|
{/if}
|
139
130
|
</span>
|
140
131
|
|
141
|
-
<span class="time">{
|
132
|
+
<span class="time">{format_time(time)} / {format_time(duration)}</span>
|
142
133
|
|
143
134
|
<!-- TODO: implement accessible video timeline for 4.0 -->
|
144
135
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
@@ -5,6 +5,7 @@
|
|
5
5
|
import { FFmpeg } from "@ffmpeg/ffmpeg";
|
6
6
|
import loadFfmpeg from "./utils";
|
7
7
|
import { onMount } from "svelte";
|
8
|
+
import { format_time } from "@gradio/utils";
|
8
9
|
|
9
10
|
export let videoElement: HTMLVideoElement;
|
10
11
|
|
@@ -24,18 +25,6 @@
|
|
24
25
|
$: if (mode === "edit" && trimmedDuration === null && videoElement)
|
25
26
|
trimmedDuration = videoElement.duration;
|
26
27
|
|
27
|
-
const formatTime = (seconds: number): string => {
|
28
|
-
const minutes = Math.floor(seconds / 60);
|
29
|
-
const secondsRemainder = Math.round(seconds) % 60;
|
30
|
-
const paddedSeconds = `0${secondsRemainder}`.slice(-2);
|
31
|
-
|
32
|
-
if (Number.isNaN(minutes) || Number.isNaN(secondsRemainder)) {
|
33
|
-
return "00:00";
|
34
|
-
}
|
35
|
-
|
36
|
-
return `${minutes}:${paddedSeconds}`;
|
37
|
-
};
|
38
|
-
|
39
28
|
let trimmedDuration: number | null = null;
|
40
29
|
let dragStart = 0;
|
41
30
|
let dragEnd = 0;
|
@@ -69,7 +58,7 @@
|
|
69
58
|
{#if mode === "edit" && trimmedDuration !== null}
|
70
59
|
<time
|
71
60
|
aria-label="duration of selected region in seconds"
|
72
|
-
class:hidden={loadingTimeline}>{
|
61
|
+
class:hidden={loadingTimeline}>{format_time(trimmedDuration)}</time
|
73
62
|
>
|
74
63
|
{:else}
|
75
64
|
<div />
|