mirror of
https://code.castopod.org/adaures/castopod
synced 2025-06-06 18:31:05 +00:00
feat: add audio-clipper webcomponent (wip)
This commit is contained in:
parent
7609bb6033
commit
21d4251b9b
@ -1,5 +1,6 @@
|
|||||||
import "@github/markdown-toolbar-element";
|
import "@github/markdown-toolbar-element";
|
||||||
import "@github/time-elements";
|
import "@github/time-elements";
|
||||||
|
import "./modules/audio-clipper";
|
||||||
import ClientTimezone from "./modules/ClientTimezone";
|
import ClientTimezone from "./modules/ClientTimezone";
|
||||||
import Clipboard from "./modules/Clipboard";
|
import Clipboard from "./modules/Clipboard";
|
||||||
import DateTimePicker from "./modules/DateTimePicker";
|
import DateTimePicker from "./modules/DateTimePicker";
|
||||||
|
440
app/Resources/js/modules/audio-clipper.ts
Normal file
440
app/Resources/js/modules/audio-clipper.ts
Normal file
@ -0,0 +1,440 @@
|
|||||||
|
import { css, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
property,
|
||||||
|
query,
|
||||||
|
queryAssignedNodes,
|
||||||
|
state,
|
||||||
|
} from "lit/decorators.js";
|
||||||
|
import WaveSurfer from "wavesurfer.js";
|
||||||
|
|
||||||
|
enum ACTIONS {
|
||||||
|
StretchLeft,
|
||||||
|
StretchRight,
|
||||||
|
Seek,
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("audio-clipper")
|
||||||
|
export class AudioClipper extends LitElement {
|
||||||
|
@queryAssignedNodes("audio", true)
|
||||||
|
_audio!: NodeListOf<HTMLAudioElement>;
|
||||||
|
|
||||||
|
@queryAssignedNodes("start_time", true)
|
||||||
|
_startTimeInput!: NodeListOf<HTMLInputElement>;
|
||||||
|
|
||||||
|
@queryAssignedNodes("duration", true)
|
||||||
|
_durationInput!: NodeListOf<HTMLInputElement>;
|
||||||
|
|
||||||
|
@query(".slider")
|
||||||
|
_sliderNode!: HTMLDivElement;
|
||||||
|
|
||||||
|
@query(".slider__segment--wrapper")
|
||||||
|
_segmentNode!: HTMLDivElement;
|
||||||
|
|
||||||
|
@query(".slider__segment-content")
|
||||||
|
_segmentContentNode!: HTMLDivElement;
|
||||||
|
|
||||||
|
@query(".slider__segment-progress-handle")
|
||||||
|
_progressNode!: HTMLDivElement;
|
||||||
|
|
||||||
|
@query("#waveform")
|
||||||
|
_waveformNode!: HTMLDivElement;
|
||||||
|
|
||||||
|
@property({ type: Number, attribute: "start-time" })
|
||||||
|
startTime = 0;
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
duration = 10;
|
||||||
|
|
||||||
|
@property({ type: Number, attribute: "min-duration" })
|
||||||
|
minDuration = 5;
|
||||||
|
|
||||||
|
@property({ type: Number, attribute: "volume" })
|
||||||
|
initVolume = 0.5;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_isPlaying = false;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_clip = {
|
||||||
|
startTime: 0,
|
||||||
|
endTime: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_action: ACTIONS | null = null;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_audioDuration = 0;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_sliderWidth = 0;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_currentTime = 0;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_volume = 0.5;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
_wavesurfer!: WaveSurfer;
|
||||||
|
|
||||||
|
connectedCallback(): void {
|
||||||
|
super.connectedCallback();
|
||||||
|
|
||||||
|
console.log("connectedCallback_before");
|
||||||
|
this._clip = {
|
||||||
|
startTime: this.startTime,
|
||||||
|
endTime: this.startTime + this.duration,
|
||||||
|
};
|
||||||
|
this._volume = this.initVolume;
|
||||||
|
console.log("connectedCallback_after");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(): void {
|
||||||
|
console.log("firstUpdate");
|
||||||
|
this._audioDuration = this._audio[0].duration;
|
||||||
|
this._audio[0].volume = this._volume;
|
||||||
|
|
||||||
|
this._wavesurfer = WaveSurfer.create({
|
||||||
|
container: this._waveformNode,
|
||||||
|
interact: false,
|
||||||
|
barWidth: 2,
|
||||||
|
barHeight: 1,
|
||||||
|
responsive: true,
|
||||||
|
});
|
||||||
|
this._wavesurfer.load(this._audio[0].src);
|
||||||
|
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
this._sliderWidth = this._sliderNode.clientWidth;
|
||||||
|
this.setSegmentPosition();
|
||||||
|
});
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
this._sliderWidth = this._sliderNode.clientWidth;
|
||||||
|
this.setSegmentPosition();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("mouseup", () => {
|
||||||
|
if (this._action !== null) {
|
||||||
|
this._action = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.addEventListener("mousemove", (event: MouseEvent) => {
|
||||||
|
if (this._action !== null) {
|
||||||
|
this.updatePosition(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this._audio[0].addEventListener("play", () => {
|
||||||
|
this._isPlaying = true;
|
||||||
|
});
|
||||||
|
this._audio[0].addEventListener("pause", () => {
|
||||||
|
this._isPlaying = false;
|
||||||
|
});
|
||||||
|
// this._audio[0].addEventListener("timeupdate", () => {
|
||||||
|
// this._currentTime = this._audio[0].currentTime;
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback(): void {
|
||||||
|
console.log("disconnectedCallback");
|
||||||
|
|
||||||
|
window.removeEventListener("load", () => {
|
||||||
|
this._sliderWidth = this._sliderNode.clientWidth;
|
||||||
|
this.setSegmentPosition();
|
||||||
|
});
|
||||||
|
window.removeEventListener("resize", () => {
|
||||||
|
this._sliderWidth = this._sliderNode.clientWidth;
|
||||||
|
this.setSegmentPosition();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.removeEventListener("mouseup", () => {
|
||||||
|
if (this._action !== null) {
|
||||||
|
this._action = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.removeEventListener("mousemove", (event: MouseEvent) => {
|
||||||
|
if (this._action !== null) {
|
||||||
|
this.updatePosition(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this._audio[0].removeEventListener("play", () => {
|
||||||
|
this._isPlaying = true;
|
||||||
|
});
|
||||||
|
this._audio[0].removeEventListener("pause", () => {
|
||||||
|
this._isPlaying = false;
|
||||||
|
});
|
||||||
|
// this._audio[0].removeEventListener("timeupdate", () => {
|
||||||
|
// this._currentTime = this._audio[0].currentTime;
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
setSegmentPosition(): void {
|
||||||
|
const startTimePosition = this.getPositionFromSeconds(this._clip.startTime);
|
||||||
|
const endTimePosition = this.getPositionFromSeconds(this._clip.endTime);
|
||||||
|
|
||||||
|
this._segmentNode.style.transform = `translateX(${startTimePosition}px)`;
|
||||||
|
this._segmentContentNode.style.width = `${
|
||||||
|
endTimePosition - startTimePosition
|
||||||
|
}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPositionFromSeconds(seconds: number) {
|
||||||
|
return (seconds * this._sliderWidth) / this._audioDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSecondsFromPosition(position: number) {
|
||||||
|
return (this._audioDuration * position) / this._sliderWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(
|
||||||
|
_changedProperties: Map<string | number | symbol, unknown>
|
||||||
|
): void {
|
||||||
|
// console.log("updated", _changedProperties);
|
||||||
|
|
||||||
|
if (_changedProperties.has("_clip")) {
|
||||||
|
// console.log("CLIP", _changedProperties.get("_clip"));
|
||||||
|
this.pause();
|
||||||
|
this.setSegmentPosition();
|
||||||
|
console.log(this._clip.startTime);
|
||||||
|
this._audio[0].currentTime = 58;
|
||||||
|
console.log(this._audio[0].currentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
play(): void {
|
||||||
|
this._audio[0].play();
|
||||||
|
// setTimeout(() => {
|
||||||
|
// this.pause();
|
||||||
|
// this._audio[0].currentTime = this._clip.startTime;
|
||||||
|
// }, (this._clip.endTime - this._clip.startTime) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
pause(): void {
|
||||||
|
this._audio[0].pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePosition(event: MouseEvent): void {
|
||||||
|
const cursorPosition =
|
||||||
|
event.clientX -
|
||||||
|
(this._sliderNode.getBoundingClientRect().left +
|
||||||
|
document.documentElement.scrollLeft);
|
||||||
|
|
||||||
|
const seconds = this.getSecondsFromPosition(cursorPosition);
|
||||||
|
|
||||||
|
switch (this._action) {
|
||||||
|
case ACTIONS.StretchLeft: {
|
||||||
|
let startTime;
|
||||||
|
if (seconds > 0) {
|
||||||
|
if (seconds > this._clip.endTime - this.minDuration) {
|
||||||
|
startTime = this._clip.endTime - this.minDuration;
|
||||||
|
} else {
|
||||||
|
startTime = seconds;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
startTime = 0;
|
||||||
|
}
|
||||||
|
this._clip = {
|
||||||
|
startTime,
|
||||||
|
endTime: this._clip.endTime,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ACTIONS.StretchRight: {
|
||||||
|
let endTime;
|
||||||
|
if (seconds < this._audioDuration) {
|
||||||
|
if (seconds < this._clip.startTime + this.minDuration) {
|
||||||
|
endTime = this._clip.startTime + this.minDuration;
|
||||||
|
} else {
|
||||||
|
endTime = seconds;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
endTime = this._audioDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._clip = {
|
||||||
|
startTime: this._clip.startTime,
|
||||||
|
endTime,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ACTIONS.Seek: {
|
||||||
|
console.log("seeking");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setVolume(event: InputEvent): void {
|
||||||
|
this._volume = parseFloat((event.target as HTMLInputElement).value);
|
||||||
|
this._audio[0].volume = this._volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentTime(event: MouseEvent): void {
|
||||||
|
const cursorPosition =
|
||||||
|
event.clientX -
|
||||||
|
(this._sliderNode.getBoundingClientRect().left +
|
||||||
|
document.documentElement.scrollLeft);
|
||||||
|
|
||||||
|
const seconds = this.getSecondsFromPosition(cursorPosition);
|
||||||
|
this._audio[0].currentTime = seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAction(action: ACTIONS): void {
|
||||||
|
this._action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
secondsToHHMMSS(seconds: number): string {
|
||||||
|
return new Date(seconds * 1000).toISOString().substr(11, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
.slider {
|
||||||
|
position: relative;
|
||||||
|
height: 6rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider__track-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider__segment--wrapper {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider__segment {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider__segment-content {
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
height: 4rem;
|
||||||
|
width: 1px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider__segment-progress-handle {
|
||||||
|
position: absolute;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
margin-top: -9px;
|
||||||
|
margin-left: -4px;
|
||||||
|
background-color: #3b82f6;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider__segment .slider__segment-handle {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 1rem;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #b91c1c;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider__segment .slider__segment-handle::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
height: 3rem;
|
||||||
|
width: 2px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
margin: auto;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider__segment .clipper__handle-left {
|
||||||
|
left: -1rem;
|
||||||
|
border-radius: 0.2rem 0 0 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider__segment .clipper__handle-right {
|
||||||
|
right: -1rem;
|
||||||
|
border-radius: 0 0.2rem 0.2rem 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
render(): TemplateResult<1> {
|
||||||
|
return html`
|
||||||
|
<slot name="audio"></slot>
|
||||||
|
<slot name="start_time"></slot>
|
||||||
|
<slot name="duration"></slot>
|
||||||
|
<div>${this.secondsToHHMMSS(this._clip.startTime)}</div>
|
||||||
|
<div>${this.secondsToHHMMSS(this._currentTime)}</div>
|
||||||
|
<div>${this.secondsToHHMMSS(this._clip.endTime)}</div>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
id="volume"
|
||||||
|
min="0"
|
||||||
|
max="1"
|
||||||
|
step="0.1"
|
||||||
|
value="${this._volume}"
|
||||||
|
@change="${this.setVolume}"
|
||||||
|
/>
|
||||||
|
<div id="waveform"></div>
|
||||||
|
<div class="slider" role="slider">
|
||||||
|
<div class="slider__track-placeholder"></div>
|
||||||
|
<div class="slider__segment--wrapper">
|
||||||
|
<div
|
||||||
|
class="slider__segment-progress-handle"
|
||||||
|
@mousedown="${() => this.setAction(ACTIONS.Seek)}"
|
||||||
|
></div>
|
||||||
|
<!-- <div class="slider__segment-progress-handle-bar"></div> -->
|
||||||
|
<div class="slider__segment">
|
||||||
|
<button
|
||||||
|
class="slider__segment-handle clipper__handle-left"
|
||||||
|
title="${this.secondsToHHMMSS(this._clip.startTime)}"
|
||||||
|
@mousedown="${() => this.setAction(ACTIONS.StretchLeft)}"
|
||||||
|
></button>
|
||||||
|
<div
|
||||||
|
class="slider__segment-content"
|
||||||
|
@click="${this.setCurrentTime}"
|
||||||
|
></div>
|
||||||
|
<button
|
||||||
|
class="slider__segment-handle clipper__handle-right"
|
||||||
|
title="${this.secondsToHHMMSS(this._clip.endTime)}"
|
||||||
|
@mousedown="${() => this.setAction(ACTIONS.StretchRight)}"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button @click="${this._isPlaying ? this.pause : this.play}">
|
||||||
|
${this._isPlaying
|
||||||
|
? html`<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
width="1em"
|
||||||
|
height="1em"
|
||||||
|
>
|
||||||
|
<g>
|
||||||
|
<path fill="none" d="M0 0h24v24H0z" />
|
||||||
|
<path d="M6 5h2v14H6V5zm10 0h2v14h-2V5z" />
|
||||||
|
</g>
|
||||||
|
</svg>`
|
||||||
|
: html` <svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
width="1em"
|
||||||
|
height="1em"
|
||||||
|
>
|
||||||
|
<path fill="none" d="M0 0h24v24H0z" />
|
||||||
|
<path
|
||||||
|
d="M7.752 5.439l10.508 6.13a.5.5 0 0 1 0 .863l-10.508 6.13A.5.5 0 0 1 7 18.128V5.871a.5.5 0 0 1 .752-.432z"
|
||||||
|
/>
|
||||||
|
</svg>`}
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
42
package-lock.json
generated
42
package-lock.json
generated
@ -29,6 +29,7 @@
|
|||||||
"leaflet.markercluster": "^1.5.3",
|
"leaflet.markercluster": "^1.5.3",
|
||||||
"lit": "^2.0.2",
|
"lit": "^2.0.2",
|
||||||
"marked": "^4.0.7",
|
"marked": "^4.0.7",
|
||||||
|
"wavesurfer.js": "^5.2.0",
|
||||||
"xml-formatter": "^2.5.1"
|
"xml-formatter": "^2.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -43,6 +44,7 @@
|
|||||||
"@tailwindcss/typography": "^0.5.0-alpha.3",
|
"@tailwindcss/typography": "^0.5.0-alpha.3",
|
||||||
"@types/leaflet": "^1.7.6",
|
"@types/leaflet": "^1.7.6",
|
||||||
"@types/marked": "^4.0.1",
|
"@types/marked": "^4.0.1",
|
||||||
|
"@types/wavesurfer.js": "^5.2.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
||||||
"@typescript-eslint/parser": "^5.7.0",
|
"@typescript-eslint/parser": "^5.7.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
@ -3248,6 +3250,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/debounce": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-epMsEE85fi4lfmJUH/89/iV/LI+F5CvNIvmgs5g5jYFPfhO2S/ae8WSsLOKWdwtoaZw9Q2IhJ4tQ5tFCcS/4HA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "0.0.39",
|
"version": "0.0.39",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
||||||
@ -3342,6 +3350,15 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/wavesurfer.js": {
|
||||||
|
"version": "5.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/wavesurfer.js/-/wavesurfer.js-5.2.2.tgz",
|
||||||
|
"integrity": "sha512-/vjpf81co0SK3z4F5V79fZrFPQ8pw9/fEpgkzcgNVkBa9sY0gAaYzKuaQyCX/yjVf6kc73uPtWABQuVgvpguDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/debounce": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "5.8.1",
|
"version": "5.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz",
|
||||||
@ -15895,6 +15912,11 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wavesurfer.js": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-SkPlTXfvKy+ZnEA7f7g7jn6iQg5/8mAvWpVV5vRbIS/FF9TB2ak9J7VayQfzfshOLW/CqccTiN6DDR/fZA902g=="
|
||||||
|
},
|
||||||
"node_modules/webidl-conversions": {
|
"node_modules/webidl-conversions": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
@ -18897,6 +18919,12 @@
|
|||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/debounce": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-epMsEE85fi4lfmJUH/89/iV/LI+F5CvNIvmgs5g5jYFPfhO2S/ae8WSsLOKWdwtoaZw9Q2IhJ4tQ5tFCcS/4HA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/estree": {
|
"@types/estree": {
|
||||||
"version": "0.0.39",
|
"version": "0.0.39",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
||||||
@ -18979,6 +19007,15 @@
|
|||||||
"@types/trusted-types": {
|
"@types/trusted-types": {
|
||||||
"version": "2.0.2"
|
"version": "2.0.2"
|
||||||
},
|
},
|
||||||
|
"@types/wavesurfer.js": {
|
||||||
|
"version": "5.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/wavesurfer.js/-/wavesurfer.js-5.2.2.tgz",
|
||||||
|
"integrity": "sha512-/vjpf81co0SK3z4F5V79fZrFPQ8pw9/fEpgkzcgNVkBa9sY0gAaYzKuaQyCX/yjVf6kc73uPtWABQuVgvpguDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/debounce": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@typescript-eslint/eslint-plugin": {
|
"@typescript-eslint/eslint-plugin": {
|
||||||
"version": "5.8.1",
|
"version": "5.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz",
|
||||||
@ -27308,6 +27345,11 @@
|
|||||||
"xml-name-validator": "^3.0.0"
|
"xml-name-validator": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"wavesurfer.js": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wavesurfer.js/-/wavesurfer.js-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-SkPlTXfvKy+ZnEA7f7g7jn6iQg5/8mAvWpVV5vRbIS/FF9TB2ak9J7VayQfzfshOLW/CqccTiN6DDR/fZA902g=="
|
||||||
|
},
|
||||||
"webidl-conversions": {
|
"webidl-conversions": {
|
||||||
"version": "6.1.0"
|
"version": "6.1.0"
|
||||||
},
|
},
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
"leaflet.markercluster": "^1.5.3",
|
"leaflet.markercluster": "^1.5.3",
|
||||||
"lit": "^2.0.2",
|
"lit": "^2.0.2",
|
||||||
"marked": "^4.0.7",
|
"marked": "^4.0.7",
|
||||||
|
"wavesurfer.js": "^5.2.0",
|
||||||
"xml-formatter": "^2.5.1"
|
"xml-formatter": "^2.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -61,6 +62,7 @@
|
|||||||
"@tailwindcss/typography": "^0.5.0-alpha.3",
|
"@tailwindcss/typography": "^0.5.0-alpha.3",
|
||||||
"@types/leaflet": "^1.7.6",
|
"@types/leaflet": "^1.7.6",
|
||||||
"@types/marked": "^4.0.1",
|
"@types/marked": "^4.0.1",
|
||||||
|
"@types/wavesurfer.js": "^5.2.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
||||||
"@typescript-eslint/parser": "^5.7.0",
|
"@typescript-eslint/parser": "^5.7.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
|
@ -10,9 +10,20 @@
|
|||||||
|
|
||||||
<?= $this->section('content') ?>
|
<?= $this->section('content') ?>
|
||||||
|
|
||||||
<form action="<?= route_to('video-clips-create', $podcast->id, $episode->id) ?>" method="POST" class="flex flex-col gap-y-4">
|
<form action="<?= route_to('video-clips-create', $podcast->id, $episode->id) ?>" method="POST" class="flex gap-4">
|
||||||
|
|
||||||
<Forms.Section title="<?= lang('VideoClip.form.params_section_title') ?>" >
|
<div class="flex-1 w-full">
|
||||||
|
<!-- <div class="h-full bg-black"></div> -->
|
||||||
|
<audio-clipper start-time="1000" duration="140" min-duration="10" volume=".25">
|
||||||
|
<audio slot="audio" src="<?= $episode->audio->file_url ?>" class="w-full">
|
||||||
|
Your browser does not support the <code>audio</code> element.
|
||||||
|
</audio>
|
||||||
|
<input slot="start_time" type="number" name="start_time" placeholder="<?= lang('VideoClip.form.start_time') ?>" step="0.001" />
|
||||||
|
<input slot="duration" type="number" name="duration" placeholder="<?= lang('VideoClip.form.duration') ?>" step="0.001" />
|
||||||
|
</audio-clipper>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <Forms.Section title="<?= lang('VideoClip.form.params_section_title') ?>" >
|
||||||
|
|
||||||
<Forms.Field
|
<Forms.Field
|
||||||
name="label"
|
name="label"
|
||||||
@ -49,26 +60,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<div class="flex flex-col gap-x-2 gap-y-4 md:flex-row">
|
|
||||||
<Forms.Field
|
|
||||||
type="number"
|
|
||||||
name="start_time"
|
|
||||||
label="<?= lang('VideoClip.form.start_time') ?>"
|
|
||||||
required="true"
|
|
||||||
step="0.001"
|
|
||||||
/>
|
|
||||||
<Forms.Field
|
|
||||||
type="number"
|
|
||||||
name="duration"
|
|
||||||
label="<?= lang('VideoClip.form.duration') ?>"
|
|
||||||
required="true"
|
|
||||||
step="0.001"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button variant="primary" type="submit" iconRight="arrow-right" class="self-end"><?= lang('VideoClip.form.submit') ?></Button>
|
<Button variant="primary" type="submit" iconRight="arrow-right" class="self-end"><?= lang('VideoClip.form.submit') ?></Button>
|
||||||
|
|
||||||
</Forms.Section>
|
</Forms.Section> -->
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user