editor.py aktualisiert
This commit is contained in:
@@ -213,6 +213,7 @@ h1 { margin:0 0 6px; font-size:28px; }
|
|||||||
.wave-wrap { position:relative; width:100%; height:240px; background:#0b0b0b; border-radius:6px; overflow:hidden; user-select:none; touch-action:none; }
|
.wave-wrap { position:relative; width:100%; height:240px; background:#0b0b0b; border-radius:6px; overflow:hidden; user-select:none; touch-action:none; }
|
||||||
.wave-wrap img { width:100%; height:100%; object-fit:fill; display:block; opacity:.9; }
|
.wave-wrap img { width:100%; height:100%; object-fit:fill; display:block; opacity:.9; }
|
||||||
.selection { position:absolute; top:0; bottom:0; background:rgba(80,150,255,.16); border-left:2px solid #fff; border-right:2px solid #fff; pointer-events:none; }
|
.selection { position:absolute; top:0; bottom:0; background:rgba(80,150,255,.16); border-left:2px solid #fff; border-right:2px solid #fff; pointer-events:none; }
|
||||||
|
.playhead { position:absolute; top:0; bottom:0; width:2px; margin-left:-1px; background:#ffcc33; box-shadow:0 0 5px #000; z-index:4; pointer-events:none; }
|
||||||
.handle { position:absolute; top:0; bottom:0; width:18px; margin-left:-9px; cursor:ew-resize; z-index:3; touch-action:none; }
|
.handle { position:absolute; top:0; bottom:0; width:18px; margin-left:-9px; cursor:ew-resize; z-index:3; touch-action:none; }
|
||||||
.handle::after { content:""; position:absolute; left:7px; top:0; bottom:0; width:4px; background:#fff; border-radius:2px; box-shadow:0 0 5px #000; }
|
.handle::after { content:""; position:absolute; left:7px; top:0; bottom:0; width:4px; background:#fff; border-radius:2px; box-shadow:0 0 5px #000; }
|
||||||
.time-row { display:flex; justify-content:space-between; margin-top:8px; color:#aaa; font-size:14px; }
|
.time-row { display:flex; justify-content:space-between; margin-top:8px; color:#aaa; font-size:14px; }
|
||||||
@@ -253,6 +254,7 @@ button:disabled { opacity:.45; cursor:not-allowed; }
|
|||||||
<div class="wave-wrap" id="wave">
|
<div class="wave-wrap" id="wave">
|
||||||
<img src="{{ waveform_url }}" alt="Wellenform">
|
<img src="{{ waveform_url }}" alt="Wellenform">
|
||||||
<div class="selection" id="selection"></div>
|
<div class="selection" id="selection"></div>
|
||||||
|
<div class="playhead" id="playhead"></div>
|
||||||
<div class="handle" id="startHandle" title="Anfang verschieben"></div>
|
<div class="handle" id="startHandle" title="Anfang verschieben"></div>
|
||||||
<div class="handle" id="endHandle" title="Ende verschieben"></div>
|
<div class="handle" id="endHandle" title="Ende verschieben"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -267,9 +269,13 @@ button:disabled { opacity:.45; cursor:not-allowed; }
|
|||||||
|
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button onclick="jump(-10)">⏮ 10 s</button>
|
<button onclick="jump(-10)">⏮ 10 s</button>
|
||||||
|
<button onclick="jump(-1)">⏪ 1 s</button>
|
||||||
|
<button onclick="jump(1)">1 s ⏩</button>
|
||||||
<button onclick="jump(10)">10 s ⏭</button>
|
<button onclick="jump(10)">10 s ⏭</button>
|
||||||
<button onclick="playSelection()">▶ Auswahl abspielen</button>
|
<button onclick="playSelection()">▶ Auswahl abspielen</button>
|
||||||
<button onclick="playFromStart()">▶ Ab Auswahlstart</button>
|
<button onclick="playFromStart()">▶ Ab Auswahlstart</button>
|
||||||
|
<button onclick="setStartAtCurrent()">⏱ Anfang = Position</button>
|
||||||
|
<button onclick="setEndAtCurrent()">⏱ Ende = Position</button>
|
||||||
<span class="position" id="position">00:00:00</span>
|
<span class="position" id="position">00:00:00</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -283,7 +289,7 @@ button:disabled { opacity:.45; cursor:not-allowed; }
|
|||||||
<button class="primary" id="trimButton" onclick="trim()">✂ Fertige Aufnahme erstellen</button>
|
<button class="primary" id="trimButton" onclick="trim()">✂ Fertige Aufnahme erstellen</button>
|
||||||
<a class="button" href="{{ audio_url }}" download>Original herunterladen</a>
|
<a class="button" href="{{ audio_url }}" download>Original herunterladen</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="info">Die erste Version der Aufnahme wird als Original auf dem Server behalten. Weitere Schnitte sind möglich und können jederzeit auf das Original zurückgesetzt werden.</div>
|
<div class="info">Die Originalaufnahme bleibt unverändert. Aus dem gewählten Bereich wird eine fertige Aufnahme im separaten Ausgabeordner erstellt.</div>
|
||||||
<div id="message" class="message"></div>
|
<div id="message" class="message"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -297,6 +303,7 @@ const wave = document.getElementById('wave');
|
|||||||
const startHandle = document.getElementById('startHandle');
|
const startHandle = document.getElementById('startHandle');
|
||||||
const endHandle = document.getElementById('endHandle');
|
const endHandle = document.getElementById('endHandle');
|
||||||
const selection = document.getElementById('selection');
|
const selection = document.getElementById('selection');
|
||||||
|
const playhead = document.getElementById('playhead');
|
||||||
const audio = document.getElementById('audio');
|
const audio = document.getElementById('audio');
|
||||||
|
|
||||||
function fmt(sec) {
|
function fmt(sec) {
|
||||||
@@ -320,6 +327,11 @@ function render() {
|
|||||||
document.getElementById('startValue').textContent = fmt(start);
|
document.getElementById('startValue').textContent = fmt(start);
|
||||||
document.getElementById('endValue').textContent = fmt(end);
|
document.getElementById('endValue').textContent = fmt(end);
|
||||||
document.getElementById('keepValue').textContent = fmt(end-start);
|
document.getElementById('keepValue').textContent = fmt(end-start);
|
||||||
|
renderPlayhead();
|
||||||
|
}
|
||||||
|
function renderPlayhead() {
|
||||||
|
const t = Math.max(0, Math.min(duration, audio.currentTime || 0));
|
||||||
|
playhead.style.left = ((t/duration)*100)+'%';
|
||||||
}
|
}
|
||||||
function beginDrag(which, e) {
|
function beginDrag(which, e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -343,11 +355,31 @@ wave.addEventListener('pointerdown', e => {
|
|||||||
});
|
});
|
||||||
audio.addEventListener('timeupdate', () => {
|
audio.addEventListener('timeupdate', () => {
|
||||||
document.getElementById('position').textContent=fmt(audio.currentTime);
|
document.getElementById('position').textContent=fmt(audio.currentTime);
|
||||||
|
renderPlayhead();
|
||||||
if (audio.currentTime >= end && !audio.paused) audio.pause();
|
if (audio.currentTime >= end && !audio.paused) audio.pause();
|
||||||
});
|
});
|
||||||
function jump(sec) { audio.currentTime=Math.max(0,Math.min(duration,audio.currentTime+sec)); }
|
audio.addEventListener('seeking', renderPlayhead);
|
||||||
function playFromStart() { audio.currentTime=start; audio.play(); }
|
function jump(sec) { audio.currentTime=Math.max(0,Math.min(duration,audio.currentTime+sec)); renderPlayhead(); }
|
||||||
function playSelection() { audio.currentTime=start; audio.play(); }
|
function playFromStart() { audio.currentTime=start; renderPlayhead(); audio.play(); }
|
||||||
|
function playSelection() { audio.currentTime=start; renderPlayhead(); audio.play(); }
|
||||||
|
function setStartAtCurrent() {
|
||||||
|
const t = Math.max(0, Math.min(duration, audio.currentTime || 0));
|
||||||
|
if (t >= end - 0.5) {
|
||||||
|
msg('Der Anfang muss mindestens 0,5 s vor dem Ende liegen.', false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
start = t;
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
function setEndAtCurrent() {
|
||||||
|
const t = Math.max(0, Math.min(duration, audio.currentTime || 0));
|
||||||
|
if (t <= start + 0.5) {
|
||||||
|
msg('Das Ende muss mindestens 0,5 s nach dem Anfang liegen.', false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
end = t;
|
||||||
|
render();
|
||||||
|
}
|
||||||
function msg(text, ok) {
|
function msg(text, ok) {
|
||||||
const el=document.getElementById('message'); el.textContent=text; el.className='message '+(ok?'ok':'error');
|
const el=document.getElementById('message'); el.textContent=text; el.className='message '+(ok?'ok':'error');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user