Black'd
This commit is contained in:
parent
7e99e31f43
commit
5124f2d3ca
5 changed files with 85 additions and 39 deletions
|
@ -11,7 +11,6 @@ from .config_manager import get_config
|
|||
logging.basicConfig(stream=sys.stdout)
|
||||
logger = logging.getLogger("cli")
|
||||
|
||||
|
||||
CWD = os.getcwd()
|
||||
|
||||
|
||||
|
@ -60,8 +59,10 @@ class DateTimeAction(Action):
|
|||
raise ValueError("'%s' is not a valid datetime" % values)
|
||||
setattr(namespace, self.dest, parsed_val)
|
||||
|
||||
|
||||
code_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
def common_pre():
|
||||
prechecks = [pre_check_user, pre_check_permissions, pre_check_ffmpeg]
|
||||
configs = ["default_config.py"]
|
||||
|
|
|
@ -7,8 +7,15 @@ import logging
|
|||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from sqlalchemy import (Column, DateTime, Boolean, Integer, String, create_engine,
|
||||
inspect)
|
||||
from sqlalchemy import (
|
||||
Column,
|
||||
DateTime,
|
||||
Boolean,
|
||||
Integer,
|
||||
String,
|
||||
create_engine,
|
||||
inspect,
|
||||
)
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ TAG_LICENSE_URI = None
|
|||
# defaults
|
||||
STATIC_FILES = "static/"
|
||||
STATIC_PAGES = "pages/"
|
||||
if getattr(sys, 'frozen', False): # pyinstaller
|
||||
if getattr(sys, "frozen", False): # pyinstaller
|
||||
STATIC_FILES = os.path.join(sys._MEIPASS, STATIC_FILES)
|
||||
STATIC_PAGES = os.path.join(sys._MEIPASS, STATIC_PAGES)
|
||||
else:
|
||||
|
|
|
@ -11,6 +11,7 @@ from .config_manager import get_config
|
|||
logger = logging.getLogger("forge")
|
||||
Validator = Callable[[datetime, datetime, str], bool]
|
||||
|
||||
|
||||
def get_timefile_exact(time) -> str:
|
||||
"""
|
||||
time is of type `datetime`; it is not "rounded" to match the real file;
|
||||
|
@ -21,14 +22,14 @@ def get_timefile_exact(time) -> str:
|
|||
)
|
||||
|
||||
|
||||
def round_timefile(exact:datetime) -> datetime:
|
||||
def round_timefile(exact: datetime) -> datetime:
|
||||
"""
|
||||
This will round the datetime, so to match the file organization structure
|
||||
"""
|
||||
return datetime(exact.year, exact.month, exact.day, exact.hour)
|
||||
|
||||
|
||||
def get_timefile(exact:datetime) -> str:
|
||||
def get_timefile(exact: datetime) -> str:
|
||||
return get_timefile_exact(round_timefile(exact))
|
||||
|
||||
|
||||
|
@ -88,9 +89,17 @@ def mp3_join(named_intervals):
|
|||
cmdline += ["-t", str(len(files) * 3600 - (startskip + endskip))]
|
||||
return cmdline
|
||||
|
||||
def create_mp3(start: datetime, end: datetime, outfile: str, options={}, validator: Optional[Validator] = None, **kwargs):
|
||||
|
||||
def create_mp3(
|
||||
start: datetime,
|
||||
end: datetime,
|
||||
outfile: str,
|
||||
options={},
|
||||
validator: Optional[Validator] = None,
|
||||
**kwargs
|
||||
):
|
||||
if validator is None:
|
||||
validator = lambda s,e,f: True
|
||||
validator = lambda s, e, f: True
|
||||
intervals = [
|
||||
(get_timefile(begin), start_cut, end_cut)
|
||||
for begin, start_cut, end_cut in get_files_and_intervals(start, end)
|
||||
|
@ -126,9 +135,17 @@ def create_mp3(start: datetime, end: datetime, outfile: str, options={}, validat
|
|||
metadata_list.append("-metadata")
|
||||
metadata_list.append("%s=%s" % (tag, value))
|
||||
|
||||
prefix, suffix = os.path.basename(outfile).split('.', 1)
|
||||
tmp_file = tempfile.NamedTemporaryFile(suffix='.%s' % suffix, prefix='forge-%s' % prefix, delete=False)
|
||||
cmd = mp3_join(intervals) + metadata_list + ['-y'] + get_config()["FFMPEG_OPTIONS"] + [tmp_file.name]
|
||||
prefix, suffix = os.path.basename(outfile).split(".", 1)
|
||||
tmp_file = tempfile.NamedTemporaryFile(
|
||||
suffix=".%s" % suffix, prefix="forge-%s" % prefix, delete=False
|
||||
)
|
||||
cmd = (
|
||||
mp3_join(intervals)
|
||||
+ metadata_list
|
||||
+ ["-y"]
|
||||
+ get_config()["FFMPEG_OPTIONS"]
|
||||
+ [tmp_file.name]
|
||||
)
|
||||
logger.info("Running %s", " ".join(cmd))
|
||||
p = Popen(cmd)
|
||||
if get_config()["FORGE_TIMEOUT"] == 0:
|
||||
|
|
|
@ -39,14 +39,16 @@ def rec_sanitize(rec):
|
|||
d["endtime"] = date_write(d["endtime"])
|
||||
return d
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
global db
|
||||
common_pre()
|
||||
if get_config()['DEBUG']:
|
||||
if get_config()["DEBUG"]:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
db = RecDB(get_config()["DB_URI"])
|
||||
|
||||
|
||||
@app.get("/date/date")
|
||||
def date():
|
||||
n = datetime.now()
|
||||
|
@ -76,11 +78,13 @@ def help():
|
|||
+ "/custom?strftime=FORMAT : get now().strftime(FORMAT)"
|
||||
)
|
||||
|
||||
|
||||
class CreateInfo(BaseModel):
|
||||
starttime: Optional[str] = None
|
||||
endtime: Optional[str] = None
|
||||
name: str = ""
|
||||
|
||||
|
||||
@app.post("/api/create")
|
||||
async def create(req: CreateInfo = None):
|
||||
ret = {}
|
||||
|
@ -100,9 +104,11 @@ async def create(req: CreateInfo = None):
|
|||
"Nuova registrazione creata! (id:%d)" % ret.id, rec=rec_sanitize(rec)
|
||||
)
|
||||
|
||||
|
||||
class DeleteInfo(BaseModel):
|
||||
id: int
|
||||
|
||||
|
||||
@app.post("/api/delete")
|
||||
def delete(req: DeleteInfo):
|
||||
if db.delete(req.id):
|
||||
|
@ -113,15 +119,18 @@ def delete(req: DeleteInfo):
|
|||
|
||||
def timefield_factory():
|
||||
return int(time.time())
|
||||
|
||||
|
||||
TimeField = Field(default_factory=timefield_factory)
|
||||
|
||||
|
||||
class UpdateInfo(BaseModel):
|
||||
name: str = ""
|
||||
starttime: int =Field(default_factory=timefield_factory)
|
||||
endtime: int =Field(default_factory=timefield_factory)
|
||||
starttime: int = Field(default_factory=timefield_factory)
|
||||
endtime: int = Field(default_factory=timefield_factory)
|
||||
filename: Optional[str] = None
|
||||
|
||||
|
||||
@app.post("/api/update/{recid}")
|
||||
async def update(recid: int, req: UpdateInfo):
|
||||
newrec = {}
|
||||
|
@ -142,10 +151,12 @@ async def update(recid: int, req: UpdateInfo):
|
|||
class GenerateInfo(BaseModel):
|
||||
id: int
|
||||
|
||||
|
||||
class GenerateResponse(BaseModel):
|
||||
status: str
|
||||
message: str
|
||||
|
||||
|
||||
@app.post("/api/generate/{recid}")
|
||||
async def generate(recid: int, response: Response, background_tasks: BackgroundTasks):
|
||||
# prendiamo la rec in causa
|
||||
|
@ -162,9 +173,9 @@ async def generate(recid: int, response: Response, background_tasks: BackgroundT
|
|||
> get_config()["FORGE_MAX_DURATION"]
|
||||
):
|
||||
return JSONResponse(
|
||||
status_code = 400,
|
||||
status= "error",
|
||||
message= "The requested recording is too long"
|
||||
status_code=400,
|
||||
status="error",
|
||||
message="The requested recording is too long"
|
||||
+ " (%d seconds)" % (rec.endtime - rec.starttime).total_seconds(),
|
||||
)
|
||||
rec.filename = get_config()["AUDIO_OUTPUT_FORMAT"] % {
|
||||
|
@ -204,6 +215,7 @@ async def generate(recid: int, response: Response, background_tasks: BackgroundT
|
|||
rec=rec_sanitize(rec),
|
||||
)
|
||||
|
||||
|
||||
def get_duration(fname) -> float:
|
||||
lineout = check_output(
|
||||
[
|
||||
|
@ -214,7 +226,8 @@ def get_duration(fname) -> float:
|
|||
"format=duration",
|
||||
"-i",
|
||||
fname,
|
||||
]).split(b'\n')
|
||||
]
|
||||
).split(b"\n")
|
||||
duration = next(l for l in lineout if l.startswith(b"duration="))
|
||||
value = duration.split(b"=")[1]
|
||||
return float(value)
|
||||
|
@ -225,23 +238,30 @@ def get_validator(expected_duration_s: float, error_threshold_s: float) -> Valid
|
|||
try:
|
||||
duration = get_duration(fpath)
|
||||
except Exception as exc:
|
||||
logger.exception('Error determining duration of %s', fpath)
|
||||
logger.exception("Error determining duration of %s", fpath)
|
||||
return False
|
||||
logger.debug('expect %s to be %.1f±%.1fs, is %.1f', fpath, expected_duration_s, error_threshold_s, duration)
|
||||
logger.debug(
|
||||
"expect %s to be %.1f±%.1fs, is %.1f",
|
||||
fpath,
|
||||
expected_duration_s,
|
||||
error_threshold_s,
|
||||
duration,
|
||||
)
|
||||
if duration > expected_duration_s + error_threshold_s:
|
||||
return False
|
||||
if duration < expected_duration_s - error_threshold_s:
|
||||
return False
|
||||
return True
|
||||
|
||||
return validator
|
||||
|
||||
|
||||
def generate_mp3(db_id: int, **kwargs):
|
||||
'''creates and mark it as ready in the db'''
|
||||
if get_config()['FORGE_VERIFY']:
|
||||
"""creates and mark it as ready in the db"""
|
||||
if get_config()["FORGE_VERIFY"]:
|
||||
validator = get_validator(
|
||||
(kwargs['end'] - kwargs['start']).total_seconds(),
|
||||
get_config()['FORGE_VERIFY_THRESHOLD']
|
||||
(kwargs["end"] - kwargs["start"]).total_seconds(),
|
||||
get_config()["FORGE_VERIFY_THRESHOLD"],
|
||||
)
|
||||
retries = 10
|
||||
else:
|
||||
|
@ -250,11 +270,11 @@ def generate_mp3(db_id: int, **kwargs):
|
|||
|
||||
for i in range(retries):
|
||||
result = create_mp3(validator=validator, **kwargs)
|
||||
logger.debug('Create mp3 for %d -> %s', db_id, result)
|
||||
logger.debug("Create mp3 for %d -> %s", db_id, result)
|
||||
if result:
|
||||
break
|
||||
elif i < retries - 1:
|
||||
logger.debug("waiting %d", i+1)
|
||||
logger.debug("waiting %d", i + 1)
|
||||
time.sleep(i + 1) # waiting time increases at each retry
|
||||
else:
|
||||
logger.warning("Could not create mp3 for %d: validation failed", db_id)
|
||||
|
@ -266,7 +286,6 @@ def generate_mp3(db_id: int, **kwargs):
|
|||
return True
|
||||
|
||||
|
||||
|
||||
@app.get("/api/ready/{recid}")
|
||||
def check_job(recid: int):
|
||||
rec = db._search(_id=recid)[0]
|
||||
|
@ -279,7 +298,6 @@ def check_job(recid: int):
|
|||
return ret("WIP")
|
||||
|
||||
|
||||
|
||||
@app.get("/api/get/ongoing")
|
||||
def get_ongoing():
|
||||
return {rec.id: rec_sanitize(rec) for rec in db.get_ongoing()}
|
||||
|
@ -341,9 +359,12 @@ def serve_pages(request: Request):
|
|||
fpath = os.path.join(get_config()["STATIC_PAGES"], page)
|
||||
return FileResponse(fpath)
|
||||
|
||||
|
||||
def main_cmd(options):
|
||||
import uvicorn
|
||||
uvicorn.run(app, host=get_config()['HOST'], port=int(get_config()['PORT']))
|
||||
|
||||
uvicorn.run(app, host=get_config()["HOST"], port=int(get_config()["PORT"]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.warn("Usage of server.py is not supported anymore; use cli.py")
|
||||
|
|
Loading…
Reference in a new issue