This commit is contained in:
parent
8f4f50ec89
commit
a412932888
2 changed files with 65 additions and 38 deletions
56
main.py
56
main.py
|
@ -3,11 +3,11 @@ from datetime import timedelta
|
|||
from pathlib import Path
|
||||
from typing import Annotated, Optional
|
||||
|
||||
import aiofiles
|
||||
import podgen
|
||||
import structlog
|
||||
from fastapi import FastAPI, Form, HTTPException, Request, Response
|
||||
from fastapi.responses import FileResponse, RedirectResponse
|
||||
from fastapi import FastAPI, Form, HTTPException, Request, Response, UploadFile
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, JSONResponse, RedirectResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
import data
|
||||
|
@ -17,6 +17,9 @@ from settings import settings
|
|||
log = structlog.get_logger()
|
||||
|
||||
app = FastAPI()
|
||||
app.add_middleware(
|
||||
CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]
|
||||
)
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
audio_processor = AudioProcessor()
|
||||
|
@ -71,22 +74,48 @@ def finish_processing(
|
|||
|
||||
|
||||
@app.post("/admin/{feed_id}/upload")
|
||||
async def admin_upload_episode(request: Request, feed_id: str):
|
||||
async def admin_upload_episode(request: Request, feed_id: str, file: UploadFile):
|
||||
file_id = request.headers.get("uploader-file-id")
|
||||
chunks_total = int(request.headers.get("uploader-chunks-total"))
|
||||
chunk_number = int(request.headers.get("uploader-chunk-number"))
|
||||
episode_name = request.headers.get("name")
|
||||
|
||||
if file_id is None or episode_name is None:
|
||||
raise HTTPException(400, "Invalid request")
|
||||
|
||||
file_id = "".join(c for c in file_id if c.isalnum()).strip()
|
||||
|
||||
repo = data.load_repository()
|
||||
|
||||
if feed_id not in repo.podcasts:
|
||||
raise HTTPException(status_code=404, detail="Podcast not found")
|
||||
|
||||
try:
|
||||
filename = Path(urllib.parse.unquote(request.headers["filename"]))
|
||||
episode = data.Episode(name=filename.stem, file_size=0, file_hash="")
|
||||
is_last = (chunk_number + 1) == chunks_total
|
||||
|
||||
file_name = f"{file_id}_{chunk_number}"
|
||||
|
||||
settings.uploads_directory.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(settings.uploads_directory / file_name, "wb") as buf:
|
||||
buf.write(await file.read())
|
||||
|
||||
if is_last:
|
||||
episode = data.Episode(
|
||||
name=Path(urllib.parse.unquote(episode_name)).stem,
|
||||
file_size=0,
|
||||
file_hash="",
|
||||
)
|
||||
upload_path = settings.uploads_directory / episode.id
|
||||
async with aiofiles.open(upload_path, "wb") as f:
|
||||
async for chunk in request.stream():
|
||||
await f.write(chunk)
|
||||
with open(upload_path, "wb") as buf:
|
||||
chunk = 0
|
||||
while chunk < chunks_total:
|
||||
chunk_path = settings.uploads_directory / f"{file_id}_{chunk}"
|
||||
with open(chunk_path, "rb") as infile:
|
||||
buf.write(infile.read())
|
||||
infile.close()
|
||||
|
||||
chunk_path.unlink()
|
||||
chunk += 1
|
||||
|
||||
audio_processor.add_file(
|
||||
upload_path,
|
||||
|
@ -95,11 +124,10 @@ async def admin_upload_episode(request: Request, feed_id: str):
|
|||
feed_id, episode, duration, file_hash, file_size
|
||||
),
|
||||
)
|
||||
except Exception as e:
|
||||
log.error("Failed to upload file", error=e)
|
||||
raise HTTPException(status_code=500, detail="Something went wrong")
|
||||
|
||||
return {"ok": True}
|
||||
return JSONResponse({"message": "File Uploaded"}, status_code=200)
|
||||
|
||||
return JSONResponse({"message": "Chunk Uploaded"}, status_code=200)
|
||||
|
||||
|
||||
@app.get("/admin/{feed_id}/{episode_id}/delete")
|
||||
|
|
|
@ -46,12 +46,14 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
<script type="module">
|
||||
import HugeUploader from "https://cdn.skypack.dev/huge-uploader";
|
||||
|
||||
const resp = document.getElementById("response");
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const submitButton = document.getElementById("submitButton");
|
||||
|
||||
function reset() {
|
||||
window.reset = () => {
|
||||
resp.innerHTML = "";
|
||||
}
|
||||
|
||||
|
@ -60,7 +62,7 @@
|
|||
fileInput.disabled = !enabled;
|
||||
}
|
||||
|
||||
function go() {
|
||||
window.go = () => {
|
||||
const file = fileInput.files[0];
|
||||
if (!file) {
|
||||
return
|
||||
|
@ -68,34 +70,31 @@
|
|||
|
||||
setFormEnabled(false);
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.upload.addEventListener("progress", (event) => {
|
||||
if (event.lengthComputable) {
|
||||
const percentComplete = Math.round((event.loaded / event.total) * 100);
|
||||
resp.innerHTML = "Uploading: " + percentComplete + "%";
|
||||
const uploader = new HugeUploader({
|
||||
endpoint: "/admin/{{ id }}/upload",
|
||||
file: file,
|
||||
headers: {
|
||||
"name": encodeURI(file.name)
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener("load", () => {
|
||||
if (xhr.status === 200) {
|
||||
resp.innerHTML = "Upload complete, check back in a few minutes after the episode has processed.";
|
||||
uploader.on("error", (err) => {
|
||||
console.error("Upload error", err);
|
||||
resp.innerHTML = "Something has gone wrong!";
|
||||
setFormEnabled(true);
|
||||
});
|
||||
|
||||
uploader.on("progress", (progress) => {
|
||||
if (progress.detail == 100) return;
|
||||
resp.innerHTML = `Uploading ${progress.detail}%...`;
|
||||
});
|
||||
|
||||
uploader.on("finish", (body) => {
|
||||
console.log("Upload complete", body);
|
||||
resp.innerHTML = "Upload complete! The episode will be processed in the background. This may take a few minutes but it's safe to navigate away.";
|
||||
setFormEnabled(true);
|
||||
fileInput.value = "";
|
||||
} else {
|
||||
resp.innerHTML = "Upload failed";
|
||||
}
|
||||
setFormEnabled(true);
|
||||
});
|
||||
|
||||
xhr.addEventListener("error", () => {
|
||||
resp.innerHTML = "Upload failed";
|
||||
setFormEnabled(true);
|
||||
});
|
||||
|
||||
xhr.open("POST", "/admin/{{ id }}/upload", true);
|
||||
xhr.setRequestHeader("Content-Type", file.type);
|
||||
xhr.setRequestHeader("filename", encodeURI(file.name));
|
||||
xhr.send(file);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in a new issue