Compare commits

..

2 commits

Author SHA1 Message Date
83612909a8 Add configuration 2020-02-22 10:20:37 +01:00
b21fd61aa7 Fix episode upload 2020-02-22 09:58:06 +01:00
5 changed files with 62 additions and 21 deletions

View file

@ -1,5 +1,6 @@
from sqlalchemy import Boolean, Column, ForeignKey, Integer, Interval, String from sqlalchemy import Boolean, Column, ForeignKey, Integer, Interval, String
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from database import Base from database import Base

View file

@ -1,7 +1,6 @@
from datetime import timedelta from datetime import timedelta
from typing import List, Optional from typing import List
from fastapi import UploadFile
from pydantic import BaseModel from pydantic import BaseModel

View file

@ -1,3 +1,12 @@
UPLOAD_DIR = "data/uploads" from os import environ
SQLALCHEMY_DATABASE_URL = "sqlite:///./data/test.sqlite3" from pathlib import Path
BASE_URL = "http://localhost:8000"
from starlette.config import Config
__config = Config(environ.get("SIMPLEPODCAST_CONFIG", ".env"))
UPLOAD_DIR: Path = __config.get("UPLOAD_DIR", Path, "data/uploads")
SQLALCHEMY_DATABASE_URL: str = __config.get(
"UPLOAD_DIR", str, "sqlite:///./data/test.sqlite3"
)
PUBLIC_URL: str = __config.get("PUBLIC_URL", str, "http://localhost:8000")

View file

@ -3,7 +3,6 @@ from pathlib import Path
from typing import Dict from typing import Dict
import podgen import podgen
from fastapi import FastAPI, Depends, HTTPException, UploadFile, Form, File from fastapi import FastAPI, Depends, HTTPException, UploadFile, Form, File
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from starlette.requests import Request from starlette.requests import Request
@ -14,8 +13,8 @@ import models
import schemas import schemas
import utils import utils
from database import SessionLocal, engine from database import SessionLocal, engine
from schemas import Podcast, PodcastBase, EpisodeCreate, Episode from schemas import Podcast, PodcastBase, Episode
from settings import UPLOAD_DIR, BASE_URL from settings import UPLOAD_DIR, PUBLIC_URL
Path(UPLOAD_DIR).mkdir(parents=True, exist_ok=True) Path(UPLOAD_DIR).mkdir(parents=True, exist_ok=True)
@ -42,9 +41,13 @@ def get_db(request: Request):
@app.get("/podcast") @app.get("/podcast")
def list_podcasts(offset: int = 0, limit: int = 100, db: Session = Depends(get_db)) -> Dict[str, str]: def list_podcasts(
offset: int = 0, limit: int = 100, db: Session = Depends(get_db)
) -> Dict[str, str]:
db_podcasts = utils.get_all_podcasts(db, offset, limit) db_podcasts = utils.get_all_podcasts(db, offset, limit)
return {podcast.name: f"{BASE_URL}/podcast/{podcast.id}" for podcast in db_podcasts} return {
podcast.name: f"{PUBLIC_URL}/podcast/{podcast.id}" for podcast in db_podcasts
}
@app.get("/podcast/{podcast_id}", response_model=schemas.Podcast) @app.get("/podcast/{podcast_id}", response_model=schemas.Podcast)
@ -61,11 +64,22 @@ def create_podcast(podcast: PodcastBase, db: Session = Depends(get_db)) -> Podca
@app.post("/podcast/{podcast_id}/episode", response_model=schemas.Episode) @app.post("/podcast/{podcast_id}/episode", response_model=schemas.Episode)
def create_episode(podcast_id: int, upload_file: UploadFile = File(...), summary: str = Form(...), long_summary: str = Form(...), title: str = Form(...), subtitle: str = Form(...), duration: datetime.timedelta = Form(...), db: Session = Depends(get_db)) -> Episode: def create_episode(
podcast_id: int,
upload_file: UploadFile = File(...),
summary: str = Form(...),
long_summary: str = Form(...),
title: str = Form(...),
subtitle: str = Form(...),
duration: datetime.timedelta = Form(...),
db: Session = Depends(get_db),
) -> Episode:
db_podcast = utils.get_podcast(db, podcast_id) db_podcast = utils.get_podcast(db, podcast_id)
if db_podcast is None: if db_podcast is None:
raise HTTPException(status_code=404, detail="Podcast not found") raise HTTPException(status_code=404, detail="Podcast not found")
return utils.create_episode(db, podcast_id, summary, long_summary, title, subtitle, duration, upload_file) return utils.create_episode(
db, podcast_id, summary, long_summary, title, subtitle, duration, upload_file
)
app.mount("/download", StaticFiles(directory=str(UPLOAD_DIR)), name="download") app.mount("/download", StaticFiles(directory=str(UPLOAD_DIR)), name="download")
@ -79,7 +93,7 @@ def read_podcast_feed(podcast_id: int, db: Session = Depends(get_db)):
p = podgen.Podcast( p = podgen.Podcast(
name=db_podcast.name, name=db_podcast.name,
website=BASE_URL, website=PUBLIC_URL,
description=db_podcast.description, description=db_podcast.description,
explicit=db_podcast.explicit, explicit=db_podcast.explicit,
) )
@ -90,9 +104,7 @@ def read_podcast_feed(podcast_id: int, db: Session = Depends(get_db)):
title=db_episode.title, title=db_episode.title,
subtitle=db_episode.subtitle, subtitle=db_episode.subtitle,
media=podgen.Media( media=podgen.Media(
url=db_episode.url, url=db_episode.url, size=db_episode.size, duration=db_episode.duration
size=db_episode.size,
duration=datetime.timedelta(db_episode.duration),
), ),
) )
for db_episode in db_podcast.episodes for db_episode in db_podcast.episodes

View file

@ -1,16 +1,16 @@
import logging
import os import os
import shutil import shutil
from datetime import timedelta from datetime import timedelta
from pathlib import Path from pathlib import Path
from typing import List from typing import List
import aiofiles
from fastapi import HTTPException, UploadFile from fastapi import HTTPException, UploadFile
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
import models import models
import schemas import schemas
from settings import UPLOAD_DIR, BASE_URL from settings import UPLOAD_DIR, PUBLIC_URL
def get_all_podcasts( def get_all_podcasts(
@ -34,7 +34,14 @@ def create_podcast(db: Session, podcast: schemas.PodcastBase) -> models.Podcast:
def create_episode( def create_episode(
db: Session, podcast_id: int, summary: str, long_summary: str, title: str, subtitle: str, duration: timedelta, upload_file: UploadFile db: Session,
podcast_id: int,
summary: str,
long_summary: str,
title: str,
subtitle: str,
duration: timedelta,
upload_file: UploadFile,
) -> models.Episode: ) -> models.Episode:
db_episode = models.Episode( db_episode = models.Episode(
summary=summary, summary=summary,
@ -50,18 +57,31 @@ def create_episode(
db.commit() db.commit()
db.refresh(db_episode) db.refresh(db_episode)
filename = upload_file.filename
upload_dir = Path(UPLOAD_DIR) / f"podcast_{podcast_id}" / f"episode_{db_episode.id}" upload_dir = Path(UPLOAD_DIR) / f"podcast_{podcast_id}" / f"episode_{db_episode.id}"
upload_path = upload_dir / episode.filename upload_path = upload_dir / filename
if not upload_dir == upload_path.parent: if not upload_dir == upload_path.parent:
raise HTTPException(status_code=404, detail="Invalid filename") raise HTTPException(status_code=404, detail="Invalid filename")
try: try:
upload_dir.mkdir(parents=True, exist_ok=True)
with upload_path.open("wb") as buffer: with upload_path.open("wb") as buffer:
shutil.copyfileobj(upload_file.file, buffer) shutil.copyfileobj(upload_file.file, buffer)
except OSError as e:
db.delete(db_episode)
upload_file.file.close()
logging.exception("Unable to store upload to disk. %s", e)
raise HTTPException(500, "Unable to store upload to disk. " + str(e))
finally: finally:
upload_file.file.close() upload_file.file.close()
db_episode.url = f"{BASE_URL}/download/podcast_{podcast_id}/episode_{db_episode.id}/{episode.filename}" db_episode.url = "%s/download/podcast_%d/episode_%d/%s" % (
PUBLIC_URL,
podcast_id,
db_episode.id,
filename,
)
db_episode.size = os.path.getsize(str(upload_path)) db_episode.size = os.path.getsize(str(upload_path))
db.commit() db.commit()
db.refresh(db_episode) db.refresh(db_episode)