update
This commit is contained in:
4
Makefile
4
Makefile
@@ -47,8 +47,10 @@ build:
|
|||||||
cd frontend && npm run build
|
cd frontend && npm run build
|
||||||
|
|
||||||
# ── Produktion (auf dem Server ausführen, im Projektverzeichnis) ──────────────
|
# ── Produktion (auf dem Server ausführen, im Projektverzeichnis) ──────────────
|
||||||
|
# --force-recreate: auch MediaMTX kommt neu hoch und liest die
|
||||||
|
# mediamtx.yml frisch — sonst bleibt eine Konfigänderung ohne Wirkung
|
||||||
prod:
|
prod:
|
||||||
docker compose up -d --build
|
docker compose up -d --build --force-recreate
|
||||||
@echo "horror läuft: https://horror.marha.de"
|
@echo "horror läuft: https://horror.marha.de"
|
||||||
|
|
||||||
# Der Sync läuft im Container, ein backend/.venv gibt es dort nicht
|
# Der Sync läuft im Container, ein backend/.venv gibt es dort nicht
|
||||||
|
|||||||
@@ -354,8 +354,12 @@ async def aufnahme_loeschen(
|
|||||||
raise HTTPException(status_code=403, detail="Nur für den Host")
|
raise HTTPException(status_code=403, detail="Nur für den Host")
|
||||||
try:
|
try:
|
||||||
anzahl = await clips.aufnahme_loeschen(start, dauer)
|
anzahl = await clips.aufnahme_loeschen(start, dauer)
|
||||||
|
except httpx.HTTPStatusError as e:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=502, detail=f"MediaMTX lehnt ab ({e.response.status_code})."
|
||||||
|
)
|
||||||
except httpx.HTTPError:
|
except httpx.HTTPError:
|
||||||
raise HTTPException(status_code=502, detail="Löschen hat nicht geklappt.")
|
raise HTTPException(status_code=502, detail="Die MediaMTX-API ist nicht erreichbar.")
|
||||||
return {"segmente": anzahl}
|
return {"segmente": anzahl}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ const loeschFrage = ref(null)
|
|||||||
|
|
||||||
async function aufnahmenLaden() {
|
async function aufnahmenLaden() {
|
||||||
if (!props.host) return
|
if (!props.host) return
|
||||||
aufnahmenFehler.value = ''
|
|
||||||
loeschFrage.value = null
|
loeschFrage.value = null
|
||||||
try {
|
try {
|
||||||
const resp = await fetch('/api/aufnahmen')
|
const resp = await fetch('/api/aufnahmen')
|
||||||
@@ -96,9 +95,14 @@ async function aufnahmeLoeschen(s) {
|
|||||||
loeschFrage.value = s.start
|
loeschFrage.value = s.start
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
aufnahmenFehler.value = ''
|
||||||
const params = new URLSearchParams({ start: s.start, dauer: s.dauer })
|
const params = new URLSearchParams({ start: s.start, dauer: s.dauer })
|
||||||
const resp = await fetch(`/api/aufnahmen?${params}`, { method: 'DELETE' })
|
const resp = await fetch(`/api/aufnahmen?${params}`, { method: 'DELETE' })
|
||||||
if (!resp.ok) aufnahmenFehler.value = 'Löschen hat nicht geklappt.'
|
if (!resp.ok) {
|
||||||
|
// Die Meldung vom Server sagt, woran es lag — sie bleibt stehen
|
||||||
|
const daten = await resp.json().catch(() => ({}))
|
||||||
|
aufnahmenFehler.value = daten.detail || 'Löschen hat nicht geklappt.'
|
||||||
|
}
|
||||||
await aufnahmenLaden()
|
await aufnahmenLaden()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ const laden = ref(true)
|
|||||||
|
|
||||||
// Ausgeblendete Filme bleiben für den Host sichtbar, damit er sie
|
// Ausgeblendete Filme bleiben für den Host sichtbar, damit er sie
|
||||||
// zurückholen kann. Die Liste kommt jüngster zuerst — so liegt er links.
|
// zurückholen kann. Die Liste kommt jüngster zuerst — so liegt er links.
|
||||||
const seiten = computed(() =>
|
const seiten = computed(() => (props.host ? items.value : items.value.filter((e) => !e.hidden)))
|
||||||
props.host ? items.value : items.value.filter((e) => !e.hidden)
|
|
||||||
)
|
|
||||||
|
|
||||||
const buch = ref(null)
|
const buch = ref(null)
|
||||||
const aktuell = ref(0)
|
const aktuell = ref(0)
|
||||||
@@ -236,7 +234,7 @@ async function laden_() {
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.ich?.id,
|
() => props.ich?.id,
|
||||||
() => laden_()
|
() => laden_(),
|
||||||
)
|
)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -284,7 +282,20 @@ onUnmounted(() => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="stand">{{ aktuell + 1 }} / {{ seiten.length }}</p>
|
<p class="stand">
|
||||||
|
<button type="button" :disabled="aktuell <= 0" aria-label="Zurück" @click="blaettern(-1)">
|
||||||
|
‹
|
||||||
|
</button>
|
||||||
|
<span>{{ aktuell + 1 }} / {{ seiten.length }}</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
:disabled="aktuell >= seiten.length - 1"
|
||||||
|
aria-label="Weiter"
|
||||||
|
@click="blaettern(1)"
|
||||||
|
>
|
||||||
|
›
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -345,7 +356,10 @@ onUnmounted(() => {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -1.7rem;
|
bottom: -1.7rem;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
padding: 0.15rem 0.6rem;
|
display: flex;
|
||||||
|
gap: 0.4rem;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.15rem 0.4rem;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
@@ -353,6 +367,22 @@ onUnmounted(() => {
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stand button {
|
||||||
|
padding: 0 0.3rem;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stand button:hover:not(:disabled) {
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stand button:disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
.note {
|
.note {
|
||||||
padding: 2.5rem 0;
|
padding: 2.5rem 0;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
|
|||||||
Reference in New Issue
Block a user