2022-12-01 17:08:16 +00:00
|
|
|
import io
|
2022-05-27 17:04:33 +00:00
|
|
|
import typing as t
|
|
|
|
from pathlib import Path
|
|
|
|
|
2022-12-01 17:08:16 +00:00
|
|
|
import httpx
|
2022-05-27 17:04:33 +00:00
|
|
|
import typer
|
2022-12-02 02:14:04 +00:00
|
|
|
from rich.console import Console
|
2022-05-27 17:04:33 +00:00
|
|
|
|
2022-12-01 17:08:16 +00:00
|
|
|
try:
|
|
|
|
from importlib.metadata import version
|
|
|
|
except ImportError:
|
|
|
|
from importlib_metadata import version
|
|
|
|
|
|
|
|
__version__ = version("oxo")
|
2022-05-27 17:04:33 +00:00
|
|
|
|
|
|
|
app = typer.Typer()
|
|
|
|
|
|
|
|
BASE_URL = typer.Option("https://0x0.st", envvar="OXO_BASE_URL")
|
|
|
|
|
2022-12-02 02:14:04 +00:00
|
|
|
err_console = Console(stderr=True, color_system=None)
|
|
|
|
|
2022-05-27 17:04:33 +00:00
|
|
|
|
2022-12-02 20:49:23 +00:00
|
|
|
def post_to(
|
|
|
|
base_url: str, *, data: t.Iterable[t.Dict], expires: t.Optional[int]
|
|
|
|
) -> str:
|
2022-12-01 17:08:16 +00:00
|
|
|
retval = []
|
|
|
|
with httpx.Client() as client:
|
|
|
|
for d in data:
|
|
|
|
if isinstance(d.get("file"), io.BufferedReader):
|
2022-12-02 20:49:23 +00:00
|
|
|
if expires:
|
|
|
|
res = client.post(base_url, files=d, data={"expires": expires})
|
|
|
|
else:
|
|
|
|
res = client.post(base_url, files=d)
|
2022-12-02 02:14:04 +00:00
|
|
|
token = res.headers.get("x-token")
|
|
|
|
if token:
|
|
|
|
err_console.print(
|
|
|
|
f"To remove post, curl -Ftoken={token} -Fdelete= {res.text.strip()}"
|
|
|
|
)
|
|
|
|
err_console.print(
|
|
|
|
f"To update expiration date, curl -Ftoken={token} -Fexpires=NUMHOURS {res.text.strip()}"
|
|
|
|
)
|
2022-12-01 17:08:16 +00:00
|
|
|
else:
|
|
|
|
res = client.post(base_url, data=d)
|
|
|
|
res.raise_for_status()
|
|
|
|
retval.append(res.text.strip())
|
|
|
|
return " ".join(retval)
|
|
|
|
|
|
|
|
|
2022-12-02 02:14:04 +00:00
|
|
|
def post_files(base_url, files: t.List[Path], expires: t.Optional[int]):
|
2022-12-02 20:49:23 +00:00
|
|
|
return post_to(
|
|
|
|
base_url, data=({"file": f.open("rb")} for f in files), expires=expires
|
|
|
|
)
|
2022-12-01 17:08:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
def post_repost(base_url, urls: t.List[str]):
|
|
|
|
return post_to(base_url, data=({"url": u.strip()} for u in urls))
|
|
|
|
|
|
|
|
|
|
|
|
def post_shorten(base_url, urls: t.List[str]):
|
|
|
|
return post_to(base_url, data=({"shorten": u.strip()} for u in urls))
|
|
|
|
|
|
|
|
|
2022-05-27 17:04:33 +00:00
|
|
|
def version_callback(value: bool):
|
|
|
|
if value:
|
|
|
|
typer.echo(f"{__version__}")
|
|
|
|
raise typer.Exit()
|
|
|
|
|
|
|
|
|
|
|
|
@app.callback()
|
|
|
|
def main(
|
|
|
|
version: t.Optional[bool] = typer.Option(
|
|
|
|
None,
|
|
|
|
"--version",
|
|
|
|
callback=version_callback,
|
|
|
|
is_eager=True,
|
|
|
|
help="Show the version and exit.",
|
|
|
|
),
|
|
|
|
):
|
|
|
|
"""A command line utility for 0x0.st compliant pastebins.
|
|
|
|
|
2022-05-27 22:00:45 +00:00
|
|
|
To use a different 0x0 site, set `OXO_BASE_URL` in your environment,
|
|
|
|
or specify it in the relevant subcommand.
|
2022-05-27 17:04:33 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
@app.command()
|
|
|
|
def files(
|
|
|
|
files: t.List[Path] = typer.Argument(
|
|
|
|
..., min=1, exists=True, file_okay=True, dir_okay=False, resolve_path=True
|
|
|
|
),
|
2022-12-02 02:14:04 +00:00
|
|
|
expires: t.Optional[int] = typer.Option(
|
|
|
|
None, help="Expiration time, in hours or epoch milliseconds"
|
|
|
|
),
|
2022-05-27 17:04:33 +00:00
|
|
|
base_url: str = BASE_URL,
|
|
|
|
):
|
|
|
|
"""Upload one or more files."""
|
2022-12-02 02:14:04 +00:00
|
|
|
typer.echo(post_files(base_url, files, expires))
|
2022-05-27 17:04:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
@app.command()
|
2022-05-27 22:00:45 +00:00
|
|
|
def repost(urls: t.List[str] = typer.Argument(..., min=1), base_url=BASE_URL):
|
2022-05-27 17:04:33 +00:00
|
|
|
"""Repost one or more urls."""
|
2022-12-01 17:08:16 +00:00
|
|
|
typer.echo(post_repost(base_url, urls))
|
2022-05-27 17:04:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
@app.command()
|
2022-05-27 22:00:45 +00:00
|
|
|
def shorten(urls: t.List[str] = typer.Argument(..., min=1), base_url=BASE_URL):
|
2022-05-27 17:04:33 +00:00
|
|
|
"""Shorten one or more urls."""
|
|
|
|
if base_url == BASE_URL.default:
|
|
|
|
typer.secho(
|
|
|
|
f"Warning: shortening is often disabled "
|
2022-06-04 15:06:02 +00:00
|
|
|
f"for {base_url}, command may fail",
|
2022-05-27 17:04:33 +00:00
|
|
|
fg=typer.colors.RED,
|
2022-06-04 15:06:02 +00:00
|
|
|
err=True,
|
2022-05-27 17:04:33 +00:00
|
|
|
)
|
2022-12-01 17:08:16 +00:00
|
|
|
typer.echo(post_shorten(base_url, urls))
|