feat(e-pub): Tilføj til CWA (.epub) og Send til Audiobookshelf (.m4b)
Claude-Session: https://claude.ai/code/session_01AUj1LSMmrowcomkn1ciAgj
This commit is contained in:
@@ -93,6 +93,8 @@ EPUB_DEFAULTS = {
|
|||||||
"tools_dir": "/opt/portal/tools/e-pub", # mappen med fetch.sh m.fl.
|
"tools_dir": "/opt/portal/tools/e-pub", # mappen med fetch.sh m.fl.
|
||||||
"rp_required": True, # job fejler (exit 4) frem for at gå direkte ud uden proxy-nøgle
|
"rp_required": True, # job fejler (exit 4) frem for at gå direkte ud uden proxy-nøgle
|
||||||
"allowed_group": "", # tom = kun admins må bruge /e-pub
|
"allowed_group": "", # tom = kun admins må bruge /e-pub
|
||||||
|
"cwa_ingest_dir": "/media/cwa-ingest", # Calibre-Web Automateds indbakke (tom = ingen knap)
|
||||||
|
"abs_dir": "/media/audiobooks", # Audiobookshelf-bibliotekets mappe (tom = ingen knap)
|
||||||
}
|
}
|
||||||
|
|
||||||
GROUP_ORDER = {n: i for i, n in enumerate(
|
GROUP_ORDER = {n: i for i, n in enumerate(
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ def har_adgang(user, admin: bool) -> bool:
|
|||||||
return bool(user and gruppe and gruppe in (user.get("groups") or []))
|
return bool(user and gruppe and gruppe in (user.get("groups") or []))
|
||||||
|
|
||||||
|
|
||||||
|
def _skrivbar(d: str) -> bool:
|
||||||
|
return bool(d) and os.path.isdir(d) and os.access(d, os.W_OK | os.X_OK)
|
||||||
|
|
||||||
|
|
||||||
def tjek_opsaetning(s: dict | None = None) -> dict:
|
def tjek_opsaetning(s: dict | None = None) -> dict:
|
||||||
"""Til admin-siden: mangler der værktøjer eller programmer hvor portalen kører?"""
|
"""Til admin-siden: mangler der værktøjer eller programmer hvor portalen kører?"""
|
||||||
s = s or get_settings()
|
s = s or get_settings()
|
||||||
@@ -69,6 +73,8 @@ def tjek_opsaetning(s: dict | None = None) -> dict:
|
|||||||
"mangler_filer": [f for f in KRAEVEDE_FILER if not (d / f).is_file()],
|
"mangler_filer": [f for f in KRAEVEDE_FILER if not (d / f).is_file()],
|
||||||
"mangler_programmer": [p for p in KRAEVEDE_PROGRAMMER if not shutil.which(p, path=PATH)],
|
"mangler_programmer": [p for p in KRAEVEDE_PROGRAMMER if not shutil.which(p, path=PATH)],
|
||||||
"rp_noegle": bool(config.RP_API_KEY),
|
"rp_noegle": bool(config.RP_API_KEY),
|
||||||
|
"cwa_ok": _skrivbar(s.get("cwa_ingest_dir", "")),
|
||||||
|
"abs_ok": _skrivbar(s.get("abs_dir", "")),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -99,7 +105,7 @@ def opret(user: str, tekst: str) -> tuple[dict | None, str | None]:
|
|||||||
jid = secrets.token_urlsafe(12)
|
jid = secrets.token_urlsafe(12)
|
||||||
job = {"id": jid, "ejer": user, "input": tekst, "tilstand": "koe", "log": deque(maxlen=LOG_LINJER),
|
job = {"id": jid, "ejer": user, "input": tekst, "tilstand": "koe", "log": deque(maxlen=LOG_LINJER),
|
||||||
"besked": "", "fil": None, "filnavn": "", "stoerrelse": 0,
|
"besked": "", "fil": None, "filnavn": "", "stoerrelse": 0,
|
||||||
"oprettet": time.time(), "startet": None, "slut": None, "hentet": False}
|
"oprettet": time.time(), "startet": None, "slut": None, "hentet": False, "sendt": ""}
|
||||||
_jobs[jid] = job
|
_jobs[jid] = job
|
||||||
return job, None
|
return job, None
|
||||||
|
|
||||||
@@ -119,7 +125,7 @@ def alle_jobs() -> list[dict]:
|
|||||||
def status(j: dict) -> dict:
|
def status(j: dict) -> dict:
|
||||||
return {"id": j["id"], "tilstand": j["tilstand"], "besked": j["besked"], "log": list(j["log"])[-80:],
|
return {"id": j["id"], "tilstand": j["tilstand"], "besked": j["besked"], "log": list(j["log"])[-80:],
|
||||||
"filnavn": j["filnavn"], "stoerrelse": j["stoerrelse"], "oprettet": j["oprettet"],
|
"filnavn": j["filnavn"], "stoerrelse": j["stoerrelse"], "oprettet": j["oprettet"],
|
||||||
"startet": j["startet"], "slut": j["slut"]}
|
"startet": j["startet"], "slut": j["slut"], "sendt": j["sendt"], "kan_sende": kan_sende(j)}
|
||||||
|
|
||||||
|
|
||||||
def _mappe(j: dict) -> Path:
|
def _mappe(j: dict) -> Path:
|
||||||
@@ -250,6 +256,70 @@ def _draeb(proc) -> None:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------- videre til biblioteket ----------------
|
||||||
|
MAAL = {".epub": ("cwa", "cwa_ingest_dir", "CWA"), ".m4b": ("abs", "abs_dir", "Audiobookshelf")}
|
||||||
|
|
||||||
|
|
||||||
|
def kan_sende(j: dict) -> str:
|
||||||
|
""""cwa"/"abs" hvis den færdige fil kan sendes videre (mappen findes og kan skrives), ellers ""."""
|
||||||
|
if j["tilstand"] != "faerdig" or j["sendt"] or not j["filnavn"]:
|
||||||
|
return ""
|
||||||
|
maal = MAAL.get(Path(j["filnavn"]).suffix.lower())
|
||||||
|
return maal[0] if maal and _skrivbar(get_settings().get(maal[1], "")) else ""
|
||||||
|
|
||||||
|
|
||||||
|
def _rent_navn(t: str) -> str:
|
||||||
|
t = re.sub(r'[/\\\x00-\x1f]', " ", t).strip(" .")
|
||||||
|
return re.sub(r"\s+", " ", t)[:150] or "Ukendt"
|
||||||
|
|
||||||
|
|
||||||
|
def _ledig(p: Path) -> Path:
|
||||||
|
n = 2
|
||||||
|
ud = p
|
||||||
|
while ud.exists():
|
||||||
|
ud = p.with_name(f"{p.stem} ({n}){p.suffix}")
|
||||||
|
n += 1
|
||||||
|
return ud
|
||||||
|
|
||||||
|
|
||||||
|
def _kopier(kilde: Path, maal: Path) -> None:
|
||||||
|
# Via et skjult .part-navn og rename, så CWA/Audiobookshelf aldrig ser en halv fil.
|
||||||
|
tmp = maal.with_name("." + maal.name + ".part")
|
||||||
|
try:
|
||||||
|
shutil.copyfile(kilde, tmp)
|
||||||
|
os.chmod(tmp, 0o666)
|
||||||
|
os.replace(tmp, maal)
|
||||||
|
finally:
|
||||||
|
tmp.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def send(j: dict) -> str | None:
|
||||||
|
"""Kopiér den færdige fil til CWA's indbakke (.epub) eller Audiobookshelf (.m4b). Fejltekst eller None.
|
||||||
|
Synkron (kan være flere hundrede MB): kaldes via asyncio.to_thread."""
|
||||||
|
hvor = kan_sende(j)
|
||||||
|
if not hvor:
|
||||||
|
return "Filen kan ikke sendes videre (allerede sendt, udløbet eller ikke sat op)."
|
||||||
|
kilde = Path(j["fil"])
|
||||||
|
ext = kilde.suffix.lower()
|
||||||
|
_, noegle, navn = MAAL[ext]
|
||||||
|
rod = Path(get_settings()[noegle])
|
||||||
|
try:
|
||||||
|
if hvor == "cwa":
|
||||||
|
# CWA importerer kun små filendelser.
|
||||||
|
maal = _ledig(rod / (_rent_navn(kilde.stem) + ext))
|
||||||
|
else:
|
||||||
|
# Audiobookshelf: Forfatter/Titel/fil når navnet er "Forfatter - Titel", ellers Titel/fil.
|
||||||
|
forfatter, sep, titel = kilde.stem.partition(" - ")
|
||||||
|
mappe = rod / _rent_navn(forfatter) / _rent_navn(titel) if sep else rod / _rent_navn(kilde.stem)
|
||||||
|
mappe.mkdir(parents=True, exist_ok=True)
|
||||||
|
maal = _ledig(mappe / (_rent_navn(kilde.stem) + ext))
|
||||||
|
_kopier(kilde, maal)
|
||||||
|
except OSError as e:
|
||||||
|
return f"Kunne ikke sende til {navn}: {e.strerror or e}"
|
||||||
|
j["sendt"] = navn
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def content_type(filnavn: str) -> str:
|
def content_type(filnavn: str) -> str:
|
||||||
return CONTENT_TYPES.get(Path(filnavn).suffix.lower(), "application/octet-stream")
|
return CONTENT_TYPES.get(Path(filnavn).suffix.lower(), "application/octet-stream")
|
||||||
|
|
||||||
|
|||||||
@@ -1222,6 +1222,13 @@ async def epub_hent(request: Request, jid: str):
|
|||||||
background=BackgroundTask(epub.ryd, j, "hentet"))
|
background=BackgroundTask(epub.ryd, j, "hentet"))
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/e-pub/send/{jid}")
|
||||||
|
async def epub_send(request: Request, jid: str):
|
||||||
|
j = _epub_job(request, jid)
|
||||||
|
fejl = await asyncio.to_thread(epub.send, j)
|
||||||
|
return JSONResponse({"error": fejl, **epub.status(j)}, status_code=400 if fejl else 200)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/admin/epub", response_class=HTMLResponse)
|
@app.get("/admin/epub", response_class=HTMLResponse)
|
||||||
async def admin_epub(request: Request, saved: str = ""):
|
async def admin_epub(request: Request, saved: str = ""):
|
||||||
user = require_admin(request)
|
user = require_admin(request)
|
||||||
@@ -1243,8 +1250,9 @@ async def admin_epub_save(request: Request):
|
|||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
return config.EPUB_DEFAULTS[name]
|
return config.EPUB_DEFAULTS[name]
|
||||||
tools_dir = str(f.get("tools_dir") or "").strip()
|
tools_dir = str(f.get("tools_dir") or "").strip()
|
||||||
if not tools_dir.startswith("/"):
|
mapper = [str(f.get(k) or "").strip() for k in ("cwa_ingest_dir", "abs_dir")]
|
||||||
return RedirectResponse("/admin/epub?saved=" + urllib.parse.quote("Afvist: værktøjsmappen skal være en absolut sti"), status_code=303)
|
if not tools_dir.startswith("/") or any(m and not m.startswith("/") for m in mapper):
|
||||||
|
return RedirectResponse("/admin/epub?saved=" + urllib.parse.quote("Afvist: mapperne skal være absolutte stier"), status_code=303)
|
||||||
epub.save_settings({
|
epub.save_settings({
|
||||||
"max_concurrent_jobs": num("max_concurrent_jobs", 1, 8),
|
"max_concurrent_jobs": num("max_concurrent_jobs", 1, 8),
|
||||||
"job_timeout_seconds": num("job_timeout_seconds", 60, 3600),
|
"job_timeout_seconds": num("job_timeout_seconds", 60, 3600),
|
||||||
@@ -1252,6 +1260,8 @@ async def admin_epub_save(request: Request):
|
|||||||
"tools_dir": tools_dir.rstrip("/") or "/",
|
"tools_dir": tools_dir.rstrip("/") or "/",
|
||||||
"rp_required": f.get("rp_required") == "on",
|
"rp_required": f.get("rp_required") == "on",
|
||||||
"allowed_group": str(f.get("allowed_group") or "").strip()[:150],
|
"allowed_group": str(f.get("allowed_group") or "").strip()[:150],
|
||||||
|
"cwa_ingest_dir": str(f.get("cwa_ingest_dir") or "").strip().rstrip("/"),
|
||||||
|
"abs_dir": str(f.get("abs_dir") or "").strip().rstrip("/"),
|
||||||
})
|
})
|
||||||
return RedirectResponse("/admin/epub?saved=Indstillinger gemt", status_code=303)
|
return RedirectResponse("/admin/epub?saved=Indstillinger gemt", status_code=303)
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,10 @@
|
|||||||
<input class="wt-input" type="number" name="output_ttl_seconds" min="60" max="86400" value="{{ settings.output_ttl_seconds }}"></label>
|
<input class="wt-input" type="number" name="output_ttl_seconds" min="60" max="86400" value="{{ settings.output_ttl_seconds }}"></label>
|
||||||
<label>Værktøjsmappe
|
<label>Værktøjsmappe
|
||||||
<input class="wt-input" name="tools_dir" value="{{ settings.tools_dir }}" required></label>
|
<input class="wt-input" name="tools_dir" value="{{ settings.tools_dir }}" required></label>
|
||||||
|
<label>CWA-indbakke (tom = ingen "Tilføj til CWA"-knap){% if settings.cwa_ingest_dir and not tjek.cwa_ok %} <span class="err">findes ikke / kan ikke skrives</span>{% endif %}
|
||||||
|
<input class="wt-input" name="cwa_ingest_dir" value="{{ settings.cwa_ingest_dir }}"></label>
|
||||||
|
<label>Audiobookshelf-mappe (tom = ingen "Send til Audiobookshelf"-knap){% if settings.abs_dir and not tjek.abs_ok %} <span class="err">findes ikke / kan ikke skrives</span>{% endif %}
|
||||||
|
<input class="wt-input" name="abs_dir" value="{{ settings.abs_dir }}"></label>
|
||||||
<label><input type="checkbox" name="rp_required" {% if settings.rp_required %}checked{% endif %}>
|
<label><input type="checkbox" name="rp_required" {% if settings.rp_required %}checked{% endif %}>
|
||||||
Proxy påkrævet (job fejler i stedet for at gå direkte ud)</label>
|
Proxy påkrævet (job fejler i stedet for at gå direkte ud)</label>
|
||||||
<p><button class="wt-btn wt-btn--primary" type="submit">Gem</button></p>
|
<p><button class="wt-btn wt-btn--primary" type="submit">Gem</button></p>
|
||||||
|
|||||||
+22
-2
@@ -36,10 +36,25 @@
|
|||||||
k.className = "wt-card"; k.id = "ep-" + id; k.style.padding = "1rem 1.2rem";
|
k.className = "wt-card"; k.id = "ep-" + id; k.style.padding = "1rem 1.2rem";
|
||||||
k.innerHTML = '<p class="ep-tilstand" style="margin:0 0 .4rem;font-weight:600"></p>' +
|
k.innerHTML = '<p class="ep-tilstand" style="margin:0 0 .4rem;font-weight:600"></p>' +
|
||||||
'<p class="ep-besked wt-muted" style="margin:0 0 .4rem"></p>' +
|
'<p class="ep-besked wt-muted" style="margin:0 0 .4rem"></p>' +
|
||||||
'<p class="ep-hent" hidden style="margin:.4rem 0"><a class="wt-btn wt-btn--primary" href="/e-pub/hent/' + id + '">Hent fil</a></p>' +
|
'<div class="ep-hent" hidden><p style="margin:.4rem 0;display:flex;gap:.6rem;flex-wrap:wrap">' +
|
||||||
|
'<a class="wt-btn wt-btn--primary" href="/e-pub/hent/' + id + '">Hent fil</a>' +
|
||||||
|
'<button class="wt-btn ep-send" type="button" style="display:none"></button></p></div>' +
|
||||||
'<details><summary class="wt-muted" style="cursor:pointer">Log</summary>' +
|
'<details><summary class="wt-muted" style="cursor:pointer">Log</summary>' +
|
||||||
'<pre class="ep-log" style="max-height:16rem;overflow:auto;white-space:pre-wrap;font-size:.85em;margin:.4rem 0 0"></pre></details>';
|
'<pre class="ep-log" style="max-height:16rem;overflow:auto;white-space:pre-wrap;font-size:.85em;margin:.4rem 0 0"></pre></details>';
|
||||||
$("ep-jobs").insertBefore(k, $("ep-jobs").firstChild);
|
$("ep-jobs").insertBefore(k, $("ep-jobs").firstChild);
|
||||||
|
k.querySelector(".ep-send").addEventListener("click", function () {
|
||||||
|
var b = this;
|
||||||
|
b.disabled = true;
|
||||||
|
b.textContent = "Sender…";
|
||||||
|
fetch("/e-pub/send/" + id, { method: "POST", credentials: "same-origin" })
|
||||||
|
.then(function (r) { return r.json(); })
|
||||||
|
.then(function (st) {
|
||||||
|
if (st.error) k.querySelector(".ep-besked").textContent = st.error;
|
||||||
|
vis(st);
|
||||||
|
})
|
||||||
|
.catch(function () { k.querySelector(".ep-besked").textContent = "Kunne ikke nå serveren."; })
|
||||||
|
.finally(function () { b.disabled = false; });
|
||||||
|
});
|
||||||
k.querySelector(".ep-hent a").addEventListener("click", function () {
|
k.querySelector(".ep-hent a").addEventListener("click", function () {
|
||||||
// Filen slettes efter én hentning: knappen forsvinder, og status hentes igen om lidt.
|
// Filen slettes efter én hentning: knappen forsvinder, og status hentes igen om lidt.
|
||||||
setTimeout(function () { hent(id); }, 4000);
|
setTimeout(function () { hent(id); }, 4000);
|
||||||
@@ -52,8 +67,13 @@
|
|||||||
var t = TEKST[st.tilstand] || st.tilstand;
|
var t = TEKST[st.tilstand] || st.tilstand;
|
||||||
if (st.tilstand === "faerdig" && st.filnavn) t += " · " + st.filnavn + " (" + str(st.stoerrelse) + ")";
|
if (st.tilstand === "faerdig" && st.filnavn) t += " · " + st.filnavn + " (" + str(st.stoerrelse) + ")";
|
||||||
k.querySelector(".ep-tilstand").textContent = t;
|
k.querySelector(".ep-tilstand").textContent = t;
|
||||||
k.querySelector(".ep-besked").textContent = st.besked || "";
|
var besked = st.besked || "";
|
||||||
|
if (st.sendt) besked = "✅ Sendt til " + st.sendt + (st.tilstand === "faerdig" ? ". Du kan stadig hente filen." : ".");
|
||||||
|
if (!st.error) k.querySelector(".ep-besked").textContent = besked;
|
||||||
k.querySelector(".ep-hent").hidden = st.tilstand !== "faerdig";
|
k.querySelector(".ep-hent").hidden = st.tilstand !== "faerdig";
|
||||||
|
var send = k.querySelector(".ep-send");
|
||||||
|
send.style.display = st.kan_sende ? "" : "none";
|
||||||
|
send.textContent = st.kan_sende === "cwa" ? "Tilføj til CWA" : "Send til Audiobookshelf";
|
||||||
var log = k.querySelector(".ep-log"), nederst = log.scrollTop + log.clientHeight >= log.scrollHeight - 4;
|
var log = k.querySelector(".ep-log"), nederst = log.scrollTop + log.clientHeight >= log.scrollHeight - 4;
|
||||||
log.textContent = (st.log || []).join("\n");
|
log.textContent = (st.log || []).join("\n");
|
||||||
if (nederst) log.scrollTop = log.scrollHeight;
|
if (nederst) log.scrollTop = log.scrollHeight;
|
||||||
|
|||||||
+15
-4
@@ -13,8 +13,8 @@ for f in ("run.sh", "run-audiobook.sh", "lib.sh"):
|
|||||||
(VAERKTOEJ / "fetch.sh").write_text(r'''#!/bin/bash
|
(VAERKTOEJ / "fetch.sh").write_text(r'''#!/bin/bash
|
||||||
echo "trin 1: $1" >&2
|
echo "trin 1: $1" >&2
|
||||||
case "$1" in
|
case "$1" in
|
||||||
ok-epub*) printf 'PK' > "$PWD/Min Bog.epub"; echo "Wrote $PWD/Min Bog.epub (2 B)" >&2 ;;
|
ok-epub*) sleep 1; printf 'PK' > "$PWD/Min Bog.epub"; echo "Wrote $PWD/Min Bog.epub (2 B)" >&2 ;;
|
||||||
ok-m4b) head -c 1000 /dev/zero > "$PWD/Lydbog æøå.m4b"; printf 'trin 2\rtrin 3\n' >&2; echo "Wrote $PWD/Lydbog æøå.m4b (1000 B)" >&2 ;;
|
ok-m4b) head -c 1000 /dev/zero > "$PWD/Ane Forfatter - Lydbog æøå.m4b"; printf 'trin 2\rtrin 3\n' >&2; echo "Wrote $PWD/Ane Forfatter - Lydbog æøå.m4b (1000 B)" >&2 ;;
|
||||||
env) env | sort >&2; [ -d "$TMP" ] && [ -z "$(ls -A)" ] && touch "$PWD/env.epub" ;;
|
env) env | sort >&2; [ -d "$TMP" ] && [ -z "$(ls -A)" ] && touch "$PWD/env.epub" ;;
|
||||||
bad) exit 2 ;;
|
bad) exit 2 ;;
|
||||||
gone) exit 3 ;;
|
gone) exit 3 ;;
|
||||||
@@ -27,7 +27,10 @@ sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))
|
|||||||
os.chdir(pathlib.Path(__file__).resolve().parents[1])
|
os.chdir(pathlib.Path(__file__).resolve().parents[1])
|
||||||
import config # noqa: E402
|
import config # noqa: E402
|
||||||
config.EPUB_SETTINGS_PATH.write_text(json.dumps({"tools_dir": str(VAERKTOEJ), "job_timeout_seconds": 3,
|
config.EPUB_SETTINGS_PATH.write_text(json.dumps({"tools_dir": str(VAERKTOEJ), "job_timeout_seconds": 3,
|
||||||
"output_ttl_seconds": 4, "max_concurrent_jobs": 1}))
|
"output_ttl_seconds": 4, "max_concurrent_jobs": 1,
|
||||||
|
"cwa_ingest_dir": str(ROD / "cwa"), "abs_dir": str(ROD / "abs")}))
|
||||||
|
(ROD / "cwa").mkdir()
|
||||||
|
(ROD / "abs").mkdir()
|
||||||
import main # noqa: E402
|
import main # noqa: E402
|
||||||
import uvicorn # noqa: E402
|
import uvicorn # noqa: E402
|
||||||
import httpx # noqa: E402
|
import httpx # noqa: E402
|
||||||
@@ -71,6 +74,11 @@ b = c.post("/e-pub/start", data={"link": "ok-m4b"}).json()
|
|||||||
tjek("semafor: andet job venter i kø", c.get(f"/e-pub/status/{b['id']}").json()["tilstand"] == "koe")
|
tjek("semafor: andet job venter i kø", c.get(f"/e-pub/status/{b['id']}").json()["tilstand"] == "koe")
|
||||||
sa = vent(a["id"])
|
sa = vent(a["id"])
|
||||||
tjek("epub færdig", sa["tilstand"] == "faerdig" and sa["filnavn"] == "Min Bog.epub")
|
tjek("epub færdig", sa["tilstand"] == "faerdig" and sa["filnavn"] == "Min Bog.epub")
|
||||||
|
tjek("epub kan sendes til CWA", sa["kan_sende"] == "cwa")
|
||||||
|
r = c.post(f"/e-pub/send/{a['id']}")
|
||||||
|
tjek("sendt til CWA", r.status_code == 200 and r.json()["sendt"] == "CWA"
|
||||||
|
and (ROD / "cwa" / "Min Bog.epub").read_bytes() == b"PK" and not list((ROD / "cwa").glob(".*")))
|
||||||
|
tjek("ikke to gange", c.post(f"/e-pub/send/{a['id']}").status_code == 400)
|
||||||
r = c.get(f"/e-pub/hent/{a['id']}")
|
r = c.get(f"/e-pub/hent/{a['id']}")
|
||||||
tjek("epub content-type", r.headers["content-type"] == "application/epub+zip" and r.content == b"PK")
|
tjek("epub content-type", r.headers["content-type"] == "application/epub+zip" and r.content == b"PK")
|
||||||
tjek("filnavn i Content-Disposition", "Min%20Bog.epub" in r.headers["content-disposition"] or "Min Bog.epub" in r.headers["content-disposition"])
|
tjek("filnavn i Content-Disposition", "Min%20Bog.epub" in r.headers["content-disposition"] or "Min Bog.epub" in r.headers["content-disposition"])
|
||||||
@@ -79,7 +87,10 @@ tjek("slettet efter hentning", c.get(f"/e-pub/status/{a['id']}").json()["tilstan
|
|||||||
and not (config.EPUB_SCRATCH / a["id"]).exists())
|
and not (config.EPUB_SCRATCH / a["id"]).exists())
|
||||||
tjek("anden hentning = 410", c.get(f"/e-pub/hent/{a['id']}").status_code == 410)
|
tjek("anden hentning = 410", c.get(f"/e-pub/hent/{a['id']}").status_code == 410)
|
||||||
sb = vent(b["id"])
|
sb = vent(b["id"])
|
||||||
tjek("m4b færdig, \\r-linjer splittet", sb["filnavn"] == "Lydbog æøå.m4b" and "trin 3" in sb["log"])
|
tjek("m4b færdig, \\r-linjer splittet", sb["filnavn"] == "Ane Forfatter - Lydbog æøå.m4b" and "trin 3" in sb["log"])
|
||||||
|
r = c.post(f"/e-pub/send/{b['id']}")
|
||||||
|
tjek("m4b til Audiobookshelf som Forfatter/Titel", r.json().get("sendt") == "Audiobookshelf"
|
||||||
|
and (ROD / "abs" / "Ane Forfatter" / "Lydbog æøå" / "Ane Forfatter - Lydbog æøå.m4b").stat().st_size == 1000)
|
||||||
tjek("m4b content-type", c.get(f"/e-pub/hent/{b['id']}").headers["content-type"] == "audio/mp4")
|
tjek("m4b content-type", c.get(f"/e-pub/hent/{b['id']}").headers["content-type"] == "audio/mp4")
|
||||||
|
|
||||||
e = vent(c.post("/e-pub/start", data={"link": "env"}).json()["id"])
|
e = vent(c.post("/e-pub/start", data={"link": "env"}).json()["id"])
|
||||||
|
|||||||
Reference in New Issue
Block a user