hikari_uploader/hikari/hikari.py

138 lines
3.9 KiB
Python
Raw Normal View History

2022-02-27 04:35:40 +00:00
#!/usr/bin/env python3
import hashlib
2022-10-06 06:19:50 +00:00
from dataclasses import dataclass
2022-02-27 04:35:40 +00:00
from pathlib import Path
2022-10-06 07:39:36 +00:00
from typing import Literal
2022-02-27 04:35:40 +00:00
import pyperclip
import requests
import typer
2022-10-06 06:19:50 +00:00
from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
2022-10-06 07:39:36 +00:00
from rich.console import Console
2022-10-06 06:32:41 +00:00
from rich.progress import (BarColumn, DownloadColumn, Progress, TextColumn,
TimeRemainingColumn, TransferSpeedColumn)
2022-10-06 04:41:26 +00:00
HIKARI_BASE = "https://hikari.butaishoujo.moe"
HIKARI_URL = f"{HIKARI_BASE}/upload"
2022-02-27 04:35:40 +00:00
2022-10-06 07:39:36 +00:00
console = Console()
@dataclass
class UploadResponse:
status: Literal["exists"] | Literal["uploaded"]
url: str
2022-02-27 04:35:40 +00:00
2022-10-06 05:31:38 +00:00
def check_hash(filename: str, file: Path):
h = hashlib.sha256()
with file.open('br') as f:
while buf := f.read(1024**2):
h.update(buf)
h.hexdigest()[:8]
url = f"{HIKARI_URL}/{h.hexdigest()[:8]}"
with file.open('br') as f:
files = {'file': (filename, f.read(2048))}
with requests.post(url, files=files, stream=True) as req:
if req.status_code == 404:
return
req.raise_for_status()
2022-10-06 07:39:36 +00:00
return UploadResponse(**req.json())
2022-10-06 05:31:38 +00:00
2022-10-06 07:39:36 +00:00
def output(copy: bool, resp: UploadResponse):
2022-10-06 05:31:38 +00:00
if copy:
2022-10-06 07:39:36 +00:00
pyperclip.copy(resp.url)
action = "Copied"
elif resp.status == "exists":
action = "Found"
elif resp.status == "uploaded":
action = "Uploaded"
2022-10-06 05:31:38 +00:00
else:
2022-10-06 07:39:36 +00:00
action = ""
console.print(action, resp.url, style="bold green")
2022-10-06 05:31:38 +00:00
2022-10-06 06:19:50 +00:00
@dataclass
class ProgressMonitor:
size: int
2022-10-06 06:30:21 +00:00
filename: str
2022-10-06 06:19:50 +00:00
def __post_init__(self):
2022-10-06 06:30:21 +00:00
self.progress = Progress(
TextColumn("[bold blue]{task.fields[filename]}", justify="right"),
BarColumn(bar_width=None),
"[progress.percentage]{task.percentage:>3.1f}%",
"",
DownloadColumn(),
"",
TransferSpeedColumn(),
"",
TimeRemainingColumn(),
)
self.task = self.progress.add_task("[green]Uploading",
filename=self.filename,
total=self.size)
2022-10-06 06:19:50 +00:00
self.progress.start()
def __call__(self, monitor: MultipartEncoderMonitor):
2022-10-06 06:30:21 +00:00
progress = monitor.bytes_read
2022-10-06 06:19:50 +00:00
self.progress.update(self.task, completed=progress)
2022-02-27 04:35:40 +00:00
def upload(file: Path,
obstruct: bool = typer.Option(
False, "--obstruct", "-o",
help="Obstruct filename (by hashing)"
),
filename: str = typer.Option(
None, "--name", "-n",
help="Rename the uploaded file."
),
copy: bool = typer.Option(
False, "--copy", "-c",
help="Copy file URL to clipboard."
2022-10-06 04:41:26 +00:00
),
hash: bool = typer.Option(
2022-10-06 05:31:38 +00:00
True, "--hash/--no-hash", "-h/-H",
2022-10-06 04:41:26 +00:00
help="Hash file before uploading to avoid having to send the whole file twice."
2022-02-27 04:35:40 +00:00
)):
if copy:
pyperclip.copy("")
if obstruct:
2023-01-18 20:48:59 +00:00
filename = f"{hashlib.sha256(file.name.encode()).hexdigest()}{file.suffix}"
2022-02-27 04:35:40 +00:00
elif filename is None:
filename = file.name
2022-10-06 05:31:38 +00:00
if hash and (resp := check_hash(filename, file)):
return output(copy, resp)
2022-10-06 04:41:26 +00:00
2022-02-27 04:35:40 +00:00
with file.open('br') as f:
2022-10-06 06:19:50 +00:00
files = MultipartEncoder(
fields={'file': (filename, f)}
)
2022-10-06 06:30:21 +00:00
progress_monitor = ProgressMonitor(files.len, filename)
2022-10-06 04:41:26 +00:00
2022-10-06 06:19:50 +00:00
monitored = MultipartEncoderMonitor(files, progress_monitor)
headers = {'Content-Type': monitored.content_type}
2022-02-27 04:35:40 +00:00
2022-10-06 06:19:50 +00:00
with requests.post(HIKARI_URL,
data=monitored, # type: ignore
headers=headers) as req:
progress_monitor.progress.stop()
req.raise_for_status()
2022-10-06 07:41:42 +00:00
data = UploadResponse(**req.json())
2022-10-06 06:19:50 +00:00
output(copy, data)
2022-02-27 04:35:40 +00:00
def main():
typer.run(upload)