Spaces:
Runtime error
Runtime error
<script lang="ts"> | |
import { uploadToHuggingFace } from "@gradio/utils"; | |
import { Empty } from "@gradio/atoms"; | |
import { ShareButton, IconButton, BlockLabel } from "@gradio/atoms"; | |
import { Music } from "@gradio/icons"; | |
import type { I18nFormatter } from "@gradio/utils"; | |
import AudioPlayer from "../player/AudioPlayer.svelte"; | |
import { get_fetchable_url_or_file } from "@gradio/client"; | |
import { createEventDispatcher, onMount } from "svelte"; | |
import { FileData } from "@gradio/client"; | |
export let value: null | FileData = null; | |
export let image: null | string | FileData = null; | |
export let label: string; | |
export let show_label = true; | |
export let show_download_button = true; | |
export let show_share_button = false; | |
export let i18n: I18nFormatter; | |
export let waveform_settings = {}; | |
export let root = ""; | |
export let proxy_url: string | null = null; | |
let image_path: string; | |
$: { | |
if (image instanceof FileData) { | |
image_path = image.path; | |
} else { | |
image_path = get_fetchable_url_or_file(image, root, proxy_url); | |
} | |
} | |
const dispatch = createEventDispatcher<{ | |
change: FileData; | |
play: undefined; | |
pause: undefined; | |
end: undefined; | |
stop: undefined; | |
clear: undefined; | |
}>(); | |
$: value && dispatch("change", value); | |
let audioElement; | |
let isPlaying = false; | |
function play_audio() { | |
if (isPlaying) { | |
audioElement.pause(); | |
isPlaying = false; | |
return; | |
} else { | |
audioElement.play(); | |
isPlaying = true; | |
} | |
} | |
function handle_audio_end(): void { | |
dispatch("end"); | |
} | |
</script> | |
{#if value !== null} | |
<div class="icon-buttons"> | |
{#if show_share_button} | |
<ShareButton | |
{i18n} | |
on:error | |
on:share | |
formatter={async (value) => { | |
if (!value) return ""; | |
let url = await uploadToHuggingFace(value.url, "url"); | |
return `<audio controls src="${url}"></audio>`; | |
}} | |
{value} | |
/> | |
{/if} | |
</div> | |
<audio src={value.url} controls bind:this={audioElement} on:ended={handle_audio_end}/> | |
{#if image} | |
<div class="image-container" on:click={play_audio} role="button" tabindex="0" aria-hidden="true"> | |
<img class="image-player" src={image_path} alt="test" /> | |
{#if !isPlaying} | |
<!-- Play button --> | |
<svg class="play-icon" viewBox="0 0 24 24"> | |
<polygon points="5,3 19,12 5,21" fill="currentColor" /> | |
</svg> | |
{:else} | |
<!-- Pause button --> | |
<svg class="pause-icon" viewBox="0 0 24 24"> | |
<rect x="6" y="4" width="4" height="16" fill="currentColor" /> | |
<rect x="14" y="4" width="4" height="16" fill="currentColor" /> | |
</svg> | |
{/if} | |
<div class="circle-container waveform-image"> | |
{#each Array(15) as _, i (i)} | |
<div class={`waveform-bar ${isPlaying ? `waveform-animation-${i % 5}` : ''}`} style={`height: ${20 + (i % 5) * 10}%`}></div> | |
{/each} | |
</div> | |
</div> | |
{:else} | |
<div class="circle-container" on:click={play_audio} role="button" tabindex="0" aria-hidden="true"> | |
{#each Array(15) as _, i (i)} | |
<div class={`waveform-bar ${isPlaying ? `waveform-animation-${i % 5}` : ''}`} style={`height: ${20 + (i % 5) * 10}%`}></div> | |
{/each} | |
{#if !isPlaying} | |
<!-- Play button --> | |
<svg class="play-icon" viewBox="0 0 24 24" style="pointer-events: none;"> | |
<polygon points="5,3 19,12 5,21" fill="currentColor" /> | |
</svg> | |
{:else} | |
<!-- Pause button --> | |
<svg class="pause-icon" viewBox="0 0 24 24" style="pointer-events: none;"> | |
<rect x="6" y="4" width="4" height="16" fill="currentColor" /> | |
<rect x="14" y="4" width="4" height="16" fill="currentColor" /> | |
</svg> | |
{/if} | |
</div> | |
{/if} | |
{:else} | |
<Empty size="small"> | |
<Music /> | |
</Empty> | |
{/if} | |
<style> | |
audio { | |
display: none; | |
} | |
.image-container { | |
position: relative; | |
width: 350px; | |
height: 350px; | |
margin: auto; | |
} | |
.image-player { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
border-radius: 50%; | |
object-fit: cover; | |
} | |
.play-icon, .pause-icon { | |
color: white; | |
pointer-events: none; | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
width: 75px; | |
height: 75px; | |
transform: translate(-50%, -50%); | |
} | |
.circle-container:hover .play-icon { | |
width: 90px; | |
height: 90px; | |
} | |
.pause-icon { | |
opacity: 0; | |
transition: opacity 0.3s; | |
} | |
.image-container:hover .pause-icon, .circle-container:hover .pause-icon { | |
opacity: 1; | |
} | |
.circle-container:hover .waveform-bar { | |
opacity: 0.5; | |
} | |
.circle-container { | |
position: relative; | |
width: 350px; | |
height: 350px; | |
margin: auto; | |
border-radius: 50%; | |
background: var(--button-secondary-background-fill); | |
position: relative; | |
overflow: hidden; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
.waveform-image { | |
opacity: 0.5; | |
} | |
.waveform-bar { | |
background: black; | |
width: 2%; | |
height: 20%; | |
margin: 0 1%; | |
border-radius: 5px; | |
opacity: 0.5; | |
transform-origin: bottom; | |
} | |
.waveform-animation-0 { | |
animation: waveAnimation0 1s infinite ease-in-out; | |
opacity: 1; | |
} | |
.waveform-animation-1 { | |
animation: waveAnimation1 1.5s infinite ease-in-out; | |
opacity: 1; | |
} | |
.waveform-animation-2 { | |
animation: waveAnimation2 3s infinite ease-in-out; | |
opacity: 1; | |
} | |
.waveform-animation-3 { | |
animation: waveAnimation3 2s infinite ease-in-out; | |
opacity: 1; | |
} | |
.waveform-animation-4 { | |
animation: waveAnimation4 2.5s infinite ease-in-out; | |
opacity: 1; | |
} | |
.waveform-animation-5 { | |
animation: waveAnimation5 3.5s infinite ease-in-out; | |
opacity: 1; | |
} | |
waveAnimation0 { | |
0%, 100% { height: 50%; } | |
50% { height: 15%; } | |
} | |
waveAnimation1 { | |
0%, 100% { height: 45%; } | |
50% { height: 25%; } | |
} | |
waveAnimation2 { | |
0%, 100% { height: 40%; } | |
50% { height: 60%; } | |
} | |
waveAnimation3 { | |
0%, 100% { height: 70%; } | |
50% { height: 25%; } | |
} | |
waveAnimation4 { | |
0%, 100% { height: 25%; } | |
50% { height: 70%; } | |
} | |
waveAnimation5 { | |
0%, 100% { height: 60%; } | |
50% { height: 15%; } | |
} | |
</style> | |