Compare commits
2 commits
8f3de83e07
...
83612909a8
| Author | SHA1 | Date | |
|---|---|---|---|
| 83612909a8 | |||
| b21fd61aa7 |
5 changed files with 62 additions and 21 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
15
settings.py
15
settings.py
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
30
utils.py
30
utils.py
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue