autotako

Service to monitor moombox for completed livestream downloads to upload for distribution
git clone https://code.alwayswait.ing/autotako.git
Log | Files | Refs

commit 0be9710c9bf8b8c5e80ba8c23733c3ecc393d794
parent 8ef7208d4049c6e76fe5b3c1ed292d78b3d1e02f
Author: archiveanon <>
Date:   Fri, 17 Jan 2025 23:11:48 +0000

Implement WebDAV uploading

Diffstat:
Msrc/autotako/config.py | 8++++++++
Msrc/autotako/job_render.py | 43++++++++++++++++++++++++++++++++++++++-----
2 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/src/autotako/config.py b/src/autotako/config.py @@ -8,6 +8,7 @@ import msgspec class ChannelConfig(msgspec.Struct): id: str name: str | None = None + webdav_path: str | None = None class TorrentConfig(msgspec.Struct): @@ -24,10 +25,17 @@ class QBittorrentConfig(msgspec.Struct): default_save_path: str | None = None +class WebDavConfig(msgspec.Struct): + base_url: str + username: str + password: str + + class AppConfig(msgspec.Struct): moombox_url: str torrent: TorrentConfig channels: list[ChannelConfig] = msgspec.field(name="channel", default_factory=list) + webdav: WebDavConfig | None = None qbittorrent: QBittorrentConfig | None = None def get_channel_config_by_id(self, channel_id: str) -> ChannelConfig | None: diff --git a/src/autotako/job_render.py b/src/autotako/job_render.py @@ -10,7 +10,7 @@ import microdot # type: ignore import qbittorrentapi # type: ignore import torf # type: ignore -from .config import config_ctx +from .config import WebDavConfig, config_ctx from .database import database_ctx app = microdot.Microdot() @@ -126,6 +126,16 @@ async def do_gofile_upload(job: dict): return gofile_url +async def do_webdav_upload(webdav: WebDavConfig, filepath: pathlib.Path, target: str): + auth = httpx.BasicAuth(username=webdav.username, password=webdav.password) + async with httpx.AsyncClient(auth=auth) as client: + dest = f"{webdav.base_url}/{target}" + file_check = await client.head(dest) + if file_check.status_code == httpx.codes.NOT_FOUND: + with filepath.open("rb") as fh: + await client.put(dest, content=fh.read()) + + @app.get("/<jobid>") async def show_job(request, jobid): job = await get_moombox_job_by_id(jobid) @@ -148,6 +158,11 @@ async def show_job(request, jobid): display_date_str = display_date.strftime("%Y%m%d") torrent_name = f"[{display_date_str}] Unarchived Karaoke ({job['video_id']})" + folder_name = None + if stream_time: + folder_name = stream_time.strftime("%Y-%m-%dT%H:%MZ") + + readme_finalized = False render_kwargs = {} if job["output_paths"]: torrent_file = torrent_output_dir / f"{job['id']} ({job['video_id']}).torrent" @@ -172,8 +187,6 @@ async def show_job(request, jobid): t.write(torrent_file) t.write(torrent_output_dir / f"{torrent_name}.torrent") - # TODO punt file to remote - # send torrent to qbittorrent for seeding if config.qbittorrent: if config.qbittorrent.default_save_path: @@ -202,15 +215,35 @@ async def show_job(request, jobid): print(t.magnet(size=False)) print(t.files) - # TODO punt file to remote + # punt file to webdav remote + if config.webdav and channel and channel.webdav_path: + target_base = f"{channel.webdav_path}/{folder_name}" + task = asyncio.create_task( + do_webdav_upload( + config.webdav, torrent_file, f"{target_base}/{torrent_name}.torrent" + ) + ) + background_tasks.add(task) + task.add_done_callback(background_tasks.discard) render_kwargs["magnet_url"] = t.magnet(size=False) # punt files to gofile render_kwargs["gofile_url"] = await do_gofile_upload(job) - return await microdot.jinja.Template("job.md").render_async( + readme_finalized = True + rendered_job = await microdot.jinja.Template("job.md").render_async( job=job, author_override=channel.name if channel else None, stream_time=stream_time.strftime("%Y-%m-%dT%H:%MZ") if stream_time else "(unknown)", **render_kwargs, ) + if readme_finalized and config.webdav and channel and channel.webdav_path: + rendered_job_file = torrent_output_dir / f"{job['id']} ({job['video_id']}).md" + rendered_job_file.write_text(rendered_job) + target_base = f"{channel.webdav_path}/{folder_name}" + task = asyncio.create_task( + do_webdav_upload(config.webdav, rendered_job_file, f"{target_base}/REPORT.md") + ) + background_tasks.add(task) + task.add_done_callback(background_tasks.discard) + return rendered_job