zipline-cli 0.2.2__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {zipline_cli-0.2.2/src/zipline_cli.egg-info → zipline_cli-0.2.3}/PKG-INFO +10 -10
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/README.md +1 -1
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/pyproject.toml +61 -58
- zipline_cli-0.2.3/src/zipline/__init__.py +10 -0
- zipline_cli-0.2.2/src/zipline/__init__.py → zipline_cli-0.2.3/src/zipline/_version.py +1 -9
- zipline_cli-0.2.3/src/zipline/cli.py +215 -0
- zipline_cli-0.2.3/src/zipline/zipline.py +158 -0
- {zipline_cli-0.2.2 → zipline_cli-0.2.3/src/zipline_cli.egg-info}/PKG-INFO +10 -10
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/src/zipline_cli.egg-info/SOURCES.txt +2 -0
- zipline_cli-0.2.3/src/zipline_cli.egg-info/entry_points.txt +2 -0
- zipline_cli-0.2.2/src/zipline/zipline.py +0 -349
- zipline_cli-0.2.2/src/zipline_cli.egg-info/entry_points.txt +0 -2
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/LICENSE +0 -0
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/MANIFEST.in +0 -0
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/setup.cfg +0 -0
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/src/zipline/py.typed +0 -0
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/src/zipline_cli.egg-info/dependency_links.txt +0 -0
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/src/zipline_cli.egg-info/requires.txt +0 -0
- {zipline_cli-0.2.2 → zipline_cli-0.2.3}/src/zipline_cli.egg-info/top_level.txt +0 -0
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zipline-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Python 3 CLI File Uploader for Diced/Zipline v3/v4 Upload Server and Django Files.
|
|
5
5
|
Author: Shane
|
|
6
6
|
License: MIT License
|
|
7
|
-
Project-URL: GitHub, https://github.com/cssnr/zipline-cli
|
|
8
|
-
Project-URL: Issues, https://github.com/cssnr/zipline-cli/issues
|
|
9
7
|
Project-URL: Changelog, https://github.com/cssnr/zipline-cli/releases
|
|
8
|
+
Project-URL: Discord, https://discord.gg/wXy6m2X8wY
|
|
10
9
|
Project-URL: Documentation, https://zipline-cli.cssnr.com/
|
|
11
|
-
Project-URL: Homepage, https://cssnr.com/
|
|
12
10
|
Project-URL: Funding, https://ko-fi.com/cssnr
|
|
13
|
-
Project-URL:
|
|
11
|
+
Project-URL: GitHub, https://github.com/cssnr/zipline-cli
|
|
12
|
+
Project-URL: Homepage, https://cssnr.com/
|
|
13
|
+
Project-URL: Issues, https://github.com/cssnr/zipline-cli/issues
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Natural Language :: English
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
14
17
|
Classifier: Programming Language :: Python
|
|
15
18
|
Classifier: Programming Language :: Python :: 3
|
|
16
19
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
-
Classifier: Operating System :: OS Independent
|
|
18
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
-
Classifier: Natural Language :: English
|
|
20
|
-
Classifier: Typing :: Typed
|
|
21
20
|
Classifier: Topic :: Communications :: File Sharing
|
|
22
21
|
Classifier: Topic :: Terminals
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
23
|
Requires-Python: >=3.9
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
@@ -55,7 +55,7 @@ Dynamic: license-file
|
|
|
55
55
|
# Zipline CLI
|
|
56
56
|
|
|
57
57
|
<a title="Zipline CLI" href="https://zipline-cli.cssnr.com/" target="_blank">
|
|
58
|
-
<img alt="Zipline CLI" align="right" width="128" height="auto" src="https://
|
|
58
|
+
<img alt="Zipline CLI" align="right" width="128" height="auto" src="https://zipline-cli.cssnr.com/assets/images/logo.png"></a>
|
|
59
59
|
|
|
60
60
|
- [Quick Start](#quick-start)
|
|
61
61
|
- [Install](#install)
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
# Zipline CLI
|
|
26
26
|
|
|
27
27
|
<a title="Zipline CLI" href="https://zipline-cli.cssnr.com/" target="_blank">
|
|
28
|
-
<img alt="Zipline CLI" align="right" width="128" height="auto" src="https://
|
|
28
|
+
<img alt="Zipline CLI" align="right" width="128" height="auto" src="https://zipline-cli.cssnr.com/assets/images/logo.png"></a>
|
|
29
29
|
|
|
30
30
|
- [Quick Start](#quick-start)
|
|
31
31
|
- [Install](#install)
|
|
@@ -3,80 +3,67 @@
|
|
|
3
3
|
[project]
|
|
4
4
|
name = "zipline-cli"
|
|
5
5
|
description = "Python 3 CLI File Uploader for Diced/Zipline v3/v4 Upload Server and Django Files."
|
|
6
|
-
authors = [{ name="Shane" }]
|
|
7
6
|
readme = "README.md"
|
|
8
|
-
dynamic = ["version"]
|
|
9
7
|
requires-python = ">=3.9"
|
|
8
|
+
license = { text = "MIT License" }
|
|
9
|
+
authors = [{ name = "Shane" }]
|
|
10
10
|
classifiers = [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
"License :: OSI Approved :: MIT License",
|
|
12
|
+
"Natural Language :: English",
|
|
13
|
+
"Operating System :: OS Independent",
|
|
14
|
+
"Programming Language :: Python",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
17
|
+
"Topic :: Communications :: File Sharing",
|
|
18
|
+
"Topic :: Terminals",
|
|
19
|
+
"Typing :: Typed",
|
|
20
20
|
]
|
|
21
|
-
license = { text = "MIT License" }
|
|
22
|
-
#license = { file = "LICENSE" }
|
|
23
|
-
|
|
24
21
|
dependencies = [
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
]
|
|
29
|
-
|
|
30
|
-
[dependency-groups]
|
|
31
|
-
dev = [
|
|
32
|
-
"bandit",
|
|
33
|
-
"black",
|
|
34
|
-
"build",
|
|
35
|
-
"isort",
|
|
36
|
-
"mypy",
|
|
37
|
-
"python-decouple-typed",
|
|
38
|
-
"psycopg2",
|
|
39
|
-
"ruff",
|
|
40
|
-
"setuptools",
|
|
41
|
-
"ty",
|
|
42
|
-
"types-psycopg2",
|
|
43
|
-
"types-requests",
|
|
44
|
-
"validate-pyproject[all]",
|
|
45
|
-
"wheel",
|
|
22
|
+
"python-decouple",
|
|
23
|
+
"python-dotenv",
|
|
24
|
+
"requests",
|
|
46
25
|
]
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
zipline = "zipline.zipline:main"
|
|
26
|
+
dynamic = ["version"]
|
|
27
|
+
# license = { file = "LICENSE" }
|
|
50
28
|
|
|
51
29
|
[project.urls]
|
|
52
|
-
GitHub = "https://github.com/cssnr/zipline-cli"
|
|
53
|
-
Issues = "https://github.com/cssnr/zipline-cli/issues"
|
|
54
30
|
Changelog = "https://github.com/cssnr/zipline-cli/releases"
|
|
31
|
+
Discord = "https://discord.gg/wXy6m2X8wY"
|
|
55
32
|
Documentation = "https://zipline-cli.cssnr.com/"
|
|
56
|
-
|
|
57
|
-
Homepage = "https://cssnr.com/"
|
|
58
33
|
Funding = "https://ko-fi.com/cssnr"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# https://setuptools.pypa.io/en/latest/
|
|
63
|
-
#[tool.setuptools.package-data]
|
|
64
|
-
#actions = ["py.typed"]
|
|
65
|
-
[tool.setuptools.dynamic]
|
|
66
|
-
version = { attr = "zipline.__version__" }
|
|
67
|
-
#version = {file = "version.txt"}
|
|
34
|
+
GitHub = "https://github.com/cssnr/zipline-cli"
|
|
35
|
+
Homepage = "https://cssnr.com/"
|
|
36
|
+
Issues = "https://github.com/cssnr/zipline-cli/issues"
|
|
68
37
|
|
|
69
|
-
[
|
|
70
|
-
|
|
71
|
-
include-package-data = true
|
|
38
|
+
[project.scripts]
|
|
39
|
+
zipline = "zipline.cli:main"
|
|
72
40
|
|
|
73
|
-
[
|
|
74
|
-
|
|
41
|
+
[dependency-groups]
|
|
42
|
+
dev = [
|
|
43
|
+
"bandit",
|
|
44
|
+
"black",
|
|
45
|
+
"build",
|
|
46
|
+
"isort",
|
|
47
|
+
"mypy",
|
|
48
|
+
"psycopg2",
|
|
49
|
+
"python-decouple",
|
|
50
|
+
"python-decouple-typed",
|
|
51
|
+
"python-dotenv",
|
|
52
|
+
"requests",
|
|
53
|
+
"ruff",
|
|
54
|
+
"setuptools",
|
|
55
|
+
"tombi",
|
|
56
|
+
"ty",
|
|
57
|
+
"types-psycopg2",
|
|
58
|
+
"types-requests",
|
|
59
|
+
"validate-pyproject[all]",
|
|
60
|
+
"wheel",
|
|
61
|
+
]
|
|
75
62
|
|
|
76
63
|
# Build System
|
|
77
64
|
[build-system]
|
|
78
|
-
build-backend = "setuptools.build_meta"
|
|
79
65
|
requires = ["setuptools>=61.0", "wheel"]
|
|
66
|
+
build-backend = "setuptools.build_meta"
|
|
80
67
|
|
|
81
68
|
# Bandit
|
|
82
69
|
# https://bandit.readthedocs.io/en/latest/config.html
|
|
@@ -107,7 +94,7 @@ skip = ["venv", ".github"]
|
|
|
107
94
|
# Mypy
|
|
108
95
|
# https://mypy.readthedocs.io/en/stable/config_file.html
|
|
109
96
|
[tool.mypy]
|
|
110
|
-
#ignore_missing_imports = true
|
|
97
|
+
# ignore_missing_imports = true
|
|
111
98
|
exclude = ["venv"]
|
|
112
99
|
|
|
113
100
|
# Ruff
|
|
@@ -119,3 +106,19 @@ extend-exclude = [".github"]
|
|
|
119
106
|
|
|
120
107
|
[tool.ruff.lint]
|
|
121
108
|
select = ["E4", "E7", "E9", "F", "B", "Q"]
|
|
109
|
+
|
|
110
|
+
# Setup Tools
|
|
111
|
+
# https://setuptools.pypa.io/en/latest/
|
|
112
|
+
[tool.setuptools]
|
|
113
|
+
py-modules = ["zipline"]
|
|
114
|
+
include-package-data = true
|
|
115
|
+
|
|
116
|
+
[tool.setuptools.package-data]
|
|
117
|
+
zipline = ["py.typed"]
|
|
118
|
+
|
|
119
|
+
[tool.setuptools.dynamic]
|
|
120
|
+
version = { attr = "zipline._version.__version__" }
|
|
121
|
+
# version = {file = "version.txt"}
|
|
122
|
+
|
|
123
|
+
[tool.setuptools.packages.find]
|
|
124
|
+
where = ["src"]
|
|
@@ -2,19 +2,11 @@ import os
|
|
|
2
2
|
import re
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
try:
|
|
6
|
-
from .zipline import Zipline
|
|
7
|
-
except ImportError:
|
|
8
|
-
Zipline = None # type: ignore
|
|
9
|
-
|
|
10
|
-
|
|
11
5
|
def get_version() -> str:
|
|
12
|
-
version = os.environ.get("GITHUB_REF_NAME", "
|
|
6
|
+
version = os.environ.get("GITHUB_REF_NAME", "")
|
|
13
7
|
pattern = r"^\d+\.\d+\.\d+(?:[abc]\d*)?$"
|
|
14
8
|
match = re.match(pattern, version)
|
|
15
9
|
return version if match else "0.0.1"
|
|
16
10
|
|
|
17
11
|
|
|
18
12
|
__version__ = get_version()
|
|
19
|
-
|
|
20
|
-
__all__ = ["Zipline"]
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import io
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import secrets
|
|
6
|
+
import string
|
|
7
|
+
import sys
|
|
8
|
+
from importlib.metadata import version
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any, List, Optional, TextIO
|
|
11
|
+
|
|
12
|
+
from decouple import config
|
|
13
|
+
from dotenv import find_dotenv, load_dotenv
|
|
14
|
+
|
|
15
|
+
from zipline.zipline import Zipline, ZipURL
|
|
16
|
+
|
|
17
|
+
from . import __doc__ as package_doc
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def run() -> None:
|
|
21
|
+
zipline_file = ".zipline"
|
|
22
|
+
env_file = Path(os.path.expanduser("~")) / zipline_file
|
|
23
|
+
dotenv_path = env_file if os.path.isfile(env_file) else find_dotenv(filename=zipline_file)
|
|
24
|
+
env = load_dotenv(dotenv_path=dotenv_path)
|
|
25
|
+
|
|
26
|
+
parser = argparse.ArgumentParser(description="Zipline CLI.", epilog="Docs: https://zipline-cli.cssnr.com/")
|
|
27
|
+
parser.add_argument("files", metavar="file(s)", type=str, nargs="*", help="file(s) to upload")
|
|
28
|
+
parser.add_argument("-s", "--setup", action="store_true", default=False, help="run the interactive setup")
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"-u", "--url", metavar="ZIPLINE_URL", type=str, default=get_default(["url"]), help="Zipline server url"
|
|
31
|
+
)
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"-a",
|
|
34
|
+
"-t",
|
|
35
|
+
"--authorization",
|
|
36
|
+
"--token",
|
|
37
|
+
metavar="ZIPLINE_TOKEN",
|
|
38
|
+
type=str,
|
|
39
|
+
default=get_default(["token", "authorization"]),
|
|
40
|
+
help="Zipline access token or ZIPLINE_TOKEN",
|
|
41
|
+
)
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"-e",
|
|
44
|
+
"-x",
|
|
45
|
+
"--expires_at",
|
|
46
|
+
"--expire",
|
|
47
|
+
type=str,
|
|
48
|
+
default=get_default(["expire", "expire_at"]),
|
|
49
|
+
help="1d, 2w, etc. See: https://zipline.diced.sh/docs/guides/ms",
|
|
50
|
+
)
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"-E",
|
|
53
|
+
"--embed",
|
|
54
|
+
action="store_true",
|
|
55
|
+
default=get_default(["embed"], False, bool),
|
|
56
|
+
help="enable embeds on uploads",
|
|
57
|
+
)
|
|
58
|
+
parser.add_argument("-i", "--info", action="store_true", help="show application information")
|
|
59
|
+
parser.add_argument("-V", "--version", action="store_true", help="show the installed version")
|
|
60
|
+
args = parser.parse_args()
|
|
61
|
+
|
|
62
|
+
if args.version:
|
|
63
|
+
print(package_doc, file=sys.stderr)
|
|
64
|
+
print(version("zipline-cli"))
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
if args.info:
|
|
68
|
+
print(f"Zipline Version: {version('zipline-cli')}")
|
|
69
|
+
print(f"Config File: {env_file.absolute()}")
|
|
70
|
+
print(f"Server URL: {config('ZIPLINE_URL', '')}")
|
|
71
|
+
print(f"Token (ends in): {config('ZIPLINE_TOKEN', '')[-10:]}")
|
|
72
|
+
print(f"Expire: {config('ZIPLINE_EXPIRE', '')}")
|
|
73
|
+
print(f"Embed: {config('ZIPLINE_EMBED', '')}")
|
|
74
|
+
zipline_format = config("ZIPLINE_FORMAT", "{url}\n{raw_url}")
|
|
75
|
+
print(f"URL Format::\n{zipline_format}")
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
if args.setup:
|
|
79
|
+
setup(env_file)
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
if not env and not args.url and not args.authorization and not os.path.isfile(env_file):
|
|
83
|
+
env_file.touch()
|
|
84
|
+
print("First Run Detected, Entering Setup.")
|
|
85
|
+
setup(env_file)
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
if not args.url:
|
|
89
|
+
parser.print_help()
|
|
90
|
+
exit_error(parser, "Missing URL. Use --setup or specify --url")
|
|
91
|
+
|
|
92
|
+
if not args.authorization:
|
|
93
|
+
parser.print_help()
|
|
94
|
+
exit_error(parser, "Missing Token. Use --setup or specify --token")
|
|
95
|
+
|
|
96
|
+
if args.expires_at:
|
|
97
|
+
args.expires_at = args.expires_at.strip().lower()
|
|
98
|
+
match = re.search(r"^(\d+)(?:ms|s|m|h|d|w|y)$", args.expires_at)
|
|
99
|
+
if not match:
|
|
100
|
+
parser.print_help()
|
|
101
|
+
exit_error(parser, f"Invalid Expire Format: {args.expires_at}.")
|
|
102
|
+
|
|
103
|
+
zipline = Zipline(**vars(args))
|
|
104
|
+
|
|
105
|
+
if not args.files:
|
|
106
|
+
content: str = sys.stdin.read().rstrip("\n") + "\n"
|
|
107
|
+
text_f: TextIO = io.StringIO(content)
|
|
108
|
+
name = f"{gen_rand(8)}.txt"
|
|
109
|
+
url: ZipURL = zipline.send_file(name, text_f)
|
|
110
|
+
print(format_output(name, url))
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
exit_code = 1
|
|
114
|
+
for name in args.files:
|
|
115
|
+
if not os.path.isfile(name):
|
|
116
|
+
print(f"Warning: File Not Found: {name}")
|
|
117
|
+
continue
|
|
118
|
+
# mode: Literal["r", "rb"] = get_mode(name)
|
|
119
|
+
with open(name, "rb") as f:
|
|
120
|
+
# name, ext = os.path.splitext(os.path.basename(filename))
|
|
121
|
+
# ext = f'.{ext}' if ext else ''
|
|
122
|
+
# name = f'{name}-{gen_rand(8)}{ext}'
|
|
123
|
+
# url: str = zipline.send_file(name, f)
|
|
124
|
+
zip_url: ZipURL = zipline.send_file(name, f)
|
|
125
|
+
print(format_output(name, zip_url))
|
|
126
|
+
exit_code = 0
|
|
127
|
+
sys.exit(exit_code)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def setup(env_file: Path) -> None:
|
|
131
|
+
print("Setting up Environment File...")
|
|
132
|
+
url = input("Zipline URL: ").strip()
|
|
133
|
+
token = input("Zipline Authorization Token: ").strip()
|
|
134
|
+
if not url or not token:
|
|
135
|
+
raise ValueError("Missing URL or Token.")
|
|
136
|
+
output = f"ZIPLINE_URL={url}\nZIPLINE_TOKEN={token}\n"
|
|
137
|
+
embed = input("Enabled Embed? [Yes]/No: ").strip()
|
|
138
|
+
if not embed or embed.lower() not in ["n", "o", "no", "noo"]:
|
|
139
|
+
output += "ZIPLINE_EMBED=true\n"
|
|
140
|
+
expire = input("Default Expire? [Blank for None]: ").strip().lower()
|
|
141
|
+
if expire:
|
|
142
|
+
match = re.search(r"^(\d+)(?:ms|s|m|h|d|w|y)$", expire)
|
|
143
|
+
if not match:
|
|
144
|
+
print(f"Warning: invalid expire format: {expire}. See --help")
|
|
145
|
+
else:
|
|
146
|
+
output += f"ZIPLINE_EXPIRE={expire}\n"
|
|
147
|
+
with open(env_file, "w") as f:
|
|
148
|
+
f.write(output)
|
|
149
|
+
print(f"Setup Complete. Variables Saved to: {env_file}")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def get_default(
|
|
153
|
+
values: List[str],
|
|
154
|
+
default: Optional[Any] = None,
|
|
155
|
+
cast: type = str,
|
|
156
|
+
pre: str = "ZIPLINE_",
|
|
157
|
+
suf: str = "",
|
|
158
|
+
) -> Optional[str]:
|
|
159
|
+
"""
|
|
160
|
+
Get Default Environment Variable from List of values
|
|
161
|
+
:param values: List of Values to Check
|
|
162
|
+
:param default: Default Value if None
|
|
163
|
+
:param cast: Type to Cast Value
|
|
164
|
+
:param pre: Environment Variable Prefix
|
|
165
|
+
:param suf: Environment Variable Suffix
|
|
166
|
+
:return: Environment Variable or None
|
|
167
|
+
"""
|
|
168
|
+
for value in values:
|
|
169
|
+
result = config(f"{pre}{value.upper()}{suf}", "", cast)
|
|
170
|
+
if result:
|
|
171
|
+
return result
|
|
172
|
+
return default
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def format_output(filename: str, url: ZipURL) -> str:
|
|
176
|
+
"""
|
|
177
|
+
Format URL Output
|
|
178
|
+
:param filename: Original or File Name
|
|
179
|
+
:param url: ZipURL to Format
|
|
180
|
+
:return: Formatted Output
|
|
181
|
+
"""
|
|
182
|
+
zipline_format = config("ZIPLINE_FORMAT", "{filename}\n{url}\n{raw_url}")
|
|
183
|
+
return zipline_format.format(filename=filename, url=url, raw_url=url.raw)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def gen_rand(length: int = 4) -> str:
|
|
187
|
+
"""
|
|
188
|
+
Generate Random Streng
|
|
189
|
+
:param length: Length of String
|
|
190
|
+
:return: Random String
|
|
191
|
+
"""
|
|
192
|
+
r = "".join(secrets.choice(string.ascii_letters) for _ in range(length))
|
|
193
|
+
return "".join(r)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def exit_error(arg_parser: argparse.ArgumentParser, message: str, print_help=True):
|
|
197
|
+
# print(f"\033[31;1merror: \033[33;1m{message}\033[0m", file=sys.stderr, end="\n\n")
|
|
198
|
+
print(f"error: {message}", file=sys.stderr, end="\n\n")
|
|
199
|
+
if print_help:
|
|
200
|
+
arg_parser.print_help(sys.stderr)
|
|
201
|
+
sys.exit(1)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def main() -> None:
|
|
205
|
+
try:
|
|
206
|
+
run()
|
|
207
|
+
except KeyboardInterrupt:
|
|
208
|
+
sys.exit(1)
|
|
209
|
+
except Exception as error:
|
|
210
|
+
print("\nError: {}".format(str(error)))
|
|
211
|
+
sys.exit(1)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
if __name__ == "__main__":
|
|
215
|
+
main()
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import mimetypes
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import IO, Dict, Optional
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ZipURL(object):
|
|
9
|
+
"""
|
|
10
|
+
Zipline URL Object
|
|
11
|
+
:param file_url: Zipline File Display URL
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__slots__ = ["url", "raw"]
|
|
15
|
+
|
|
16
|
+
def __init__(self, file_url: str):
|
|
17
|
+
self.url: str = file_url
|
|
18
|
+
self.raw: str = self._get_raw(file_url)
|
|
19
|
+
|
|
20
|
+
def __repr__(self):
|
|
21
|
+
return f"<url={self.url} raw={self.raw}>"
|
|
22
|
+
|
|
23
|
+
def __str__(self):
|
|
24
|
+
return self.url
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def _get_raw(url: str) -> str:
|
|
28
|
+
try:
|
|
29
|
+
s = url.split("/", 4)
|
|
30
|
+
return f"{s[0]}//{s[2]}/r/{s[4]}"
|
|
31
|
+
except Exception: # noqa
|
|
32
|
+
return ""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Zipline(object):
|
|
36
|
+
"""
|
|
37
|
+
Zipline Python API
|
|
38
|
+
:param base_url: Zipline URL
|
|
39
|
+
:param kwargs: Zipline Headers
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
# noinspection SpellCheckingInspection
|
|
43
|
+
allowed_headers = [
|
|
44
|
+
# zipline v3
|
|
45
|
+
"format",
|
|
46
|
+
"image_compression_percent",
|
|
47
|
+
"expires_at",
|
|
48
|
+
"password",
|
|
49
|
+
"zws",
|
|
50
|
+
"embed",
|
|
51
|
+
"max_views",
|
|
52
|
+
"uploadtext",
|
|
53
|
+
"authorization",
|
|
54
|
+
"no_json",
|
|
55
|
+
"x_zipline_filename",
|
|
56
|
+
"original_name",
|
|
57
|
+
"override_domain",
|
|
58
|
+
# zipline v4
|
|
59
|
+
"x-zipline-deletes-at",
|
|
60
|
+
"x-zipline-format",
|
|
61
|
+
"x-zipline-image-compression-percent",
|
|
62
|
+
"x-zipline-password",
|
|
63
|
+
"x-zipline-max-views",
|
|
64
|
+
"x-zipline-no-json",
|
|
65
|
+
"x-zipline-original-name",
|
|
66
|
+
"x-zipline-folder",
|
|
67
|
+
"x-zipline-filename",
|
|
68
|
+
"x-zipline-domain",
|
|
69
|
+
"x-zipline-file-extension",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
def __init__(self, url: str, **kwargs):
|
|
73
|
+
self.base_url: str = url.rstrip("/")
|
|
74
|
+
self._headers: Dict[str, str] = {}
|
|
75
|
+
for header, value in kwargs.items():
|
|
76
|
+
if header.lower() not in self.allowed_headers:
|
|
77
|
+
continue
|
|
78
|
+
if value is None:
|
|
79
|
+
continue
|
|
80
|
+
key = header.replace("_", "-").title()
|
|
81
|
+
self._headers[key] = str(value)
|
|
82
|
+
|
|
83
|
+
def send_file(self, file_name: str, file_object: IO, overrides: Optional[dict] = None) -> ZipURL:
|
|
84
|
+
"""
|
|
85
|
+
Upload File to Zipline
|
|
86
|
+
:param file_name: Name of File for files tuple
|
|
87
|
+
:param file_object: File to Upload
|
|
88
|
+
:param overrides: Header Overrides
|
|
89
|
+
:return: File URL
|
|
90
|
+
"""
|
|
91
|
+
url = self.base_url + "/api/upload"
|
|
92
|
+
|
|
93
|
+
path = Path(file_name)
|
|
94
|
+
# if not path.is_file():
|
|
95
|
+
# raise ValueError(f"Not a File: {path.resolve()}")
|
|
96
|
+
|
|
97
|
+
mime_type = get_type(path)
|
|
98
|
+
# print(f"mime_type: {mime_type}")
|
|
99
|
+
files = {"file": (file_name, file_object, mime_type)}
|
|
100
|
+
headers = self._headers | overrides if overrides else self._headers
|
|
101
|
+
r = requests.post(url, headers=headers, files=files) # nosec
|
|
102
|
+
r.raise_for_status()
|
|
103
|
+
data = r.json()["files"][0]
|
|
104
|
+
if isinstance(data, dict):
|
|
105
|
+
return ZipURL(data["url"])
|
|
106
|
+
elif isinstance(data, list):
|
|
107
|
+
return ZipURL(data[0])
|
|
108
|
+
else:
|
|
109
|
+
return ZipURL(data)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def get_type(file_path: Path) -> str:
|
|
113
|
+
# Deprecated since version 3.13: Passing a file path instead of URL is soft deprecated. Use guess_file_type() for this.
|
|
114
|
+
# https://docs.python.org/3/library/mimetypes.html#mimetypes.guess_type
|
|
115
|
+
mime_type, _ = mimetypes.guess_type(file_path, strict=False)
|
|
116
|
+
if mime_type:
|
|
117
|
+
return mime_type
|
|
118
|
+
return magic_type(file_path)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def magic_type(file_path: Path) -> str: # NOSONAR
|
|
122
|
+
try:
|
|
123
|
+
with open(file_path, "rb") as file:
|
|
124
|
+
chunk = file.read(512)
|
|
125
|
+
# print(chunk)
|
|
126
|
+
if chunk[0:3] == b"\xff\xd8\xff" or chunk[6:10] in (b"JFIF", b"Exif"):
|
|
127
|
+
return "image/jpeg"
|
|
128
|
+
elif chunk.startswith(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"):
|
|
129
|
+
return "image/png"
|
|
130
|
+
elif chunk.startswith(b"RIFF") and chunk[8:12] == b"WEBP":
|
|
131
|
+
return "image/webp"
|
|
132
|
+
elif chunk.startswith((b"\x47\x49\x46\x38\x37\x61", b"\x47\x49\x46\x38\x39\x61")):
|
|
133
|
+
return "image/gif"
|
|
134
|
+
elif chunk.startswith(b"\x66\x74\x79\x70\x68\x65\x69\x63\x66\x74\79\70\6d"):
|
|
135
|
+
return "image/heic"
|
|
136
|
+
elif chunk.startswith(b"\x00\x00\x01\x00"):
|
|
137
|
+
return "image/ico"
|
|
138
|
+
|
|
139
|
+
elif chunk[3:11] in (b"\x66\x74\x79\x70\x4d\x53\x4e\x56", b"\x66\x74\x79\x70\x69\x73\x6f\x6d"):
|
|
140
|
+
return "video/mp4"
|
|
141
|
+
elif chunk[4:12] == b"ftypisom" or chunk[4:12] == b"ftypMSNV" or chunk[4:12] == b"ftypmp42":
|
|
142
|
+
return "video/mp4"
|
|
143
|
+
elif chunk.startswith(b"\x1a\x45\xdf\xa3"):
|
|
144
|
+
return "video/x-matroska"
|
|
145
|
+
elif chunk.startswith(b"\x6d\x6f\x6f\x76"):
|
|
146
|
+
return "video/quicktime"
|
|
147
|
+
|
|
148
|
+
elif chunk.startswith((b"\xff\xfb", b"\xff\xfb", b"\xff\xfb", b"\x49\x44\x33")):
|
|
149
|
+
return "audio/mp3"
|
|
150
|
+
elif chunk.startswith(b"RIFF") and chunk[8:12] == b"WAVE":
|
|
151
|
+
return "audio/wav"
|
|
152
|
+
elif chunk.startswith(b"OggS"):
|
|
153
|
+
return "application/ogg"
|
|
154
|
+
|
|
155
|
+
chunk.decode("utf-8")
|
|
156
|
+
return "text/plain"
|
|
157
|
+
except UnicodeDecodeError:
|
|
158
|
+
return "application/octet-stream"
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zipline-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Python 3 CLI File Uploader for Diced/Zipline v3/v4 Upload Server and Django Files.
|
|
5
5
|
Author: Shane
|
|
6
6
|
License: MIT License
|
|
7
|
-
Project-URL: GitHub, https://github.com/cssnr/zipline-cli
|
|
8
|
-
Project-URL: Issues, https://github.com/cssnr/zipline-cli/issues
|
|
9
7
|
Project-URL: Changelog, https://github.com/cssnr/zipline-cli/releases
|
|
8
|
+
Project-URL: Discord, https://discord.gg/wXy6m2X8wY
|
|
10
9
|
Project-URL: Documentation, https://zipline-cli.cssnr.com/
|
|
11
|
-
Project-URL: Homepage, https://cssnr.com/
|
|
12
10
|
Project-URL: Funding, https://ko-fi.com/cssnr
|
|
13
|
-
Project-URL:
|
|
11
|
+
Project-URL: GitHub, https://github.com/cssnr/zipline-cli
|
|
12
|
+
Project-URL: Homepage, https://cssnr.com/
|
|
13
|
+
Project-URL: Issues, https://github.com/cssnr/zipline-cli/issues
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Natural Language :: English
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
14
17
|
Classifier: Programming Language :: Python
|
|
15
18
|
Classifier: Programming Language :: Python :: 3
|
|
16
19
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
-
Classifier: Operating System :: OS Independent
|
|
18
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
-
Classifier: Natural Language :: English
|
|
20
|
-
Classifier: Typing :: Typed
|
|
21
20
|
Classifier: Topic :: Communications :: File Sharing
|
|
22
21
|
Classifier: Topic :: Terminals
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
23
|
Requires-Python: >=3.9
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
@@ -55,7 +55,7 @@ Dynamic: license-file
|
|
|
55
55
|
# Zipline CLI
|
|
56
56
|
|
|
57
57
|
<a title="Zipline CLI" href="https://zipline-cli.cssnr.com/" target="_blank">
|
|
58
|
-
<img alt="Zipline CLI" align="right" width="128" height="auto" src="https://
|
|
58
|
+
<img alt="Zipline CLI" align="right" width="128" height="auto" src="https://zipline-cli.cssnr.com/assets/images/logo.png"></a>
|
|
59
59
|
|
|
60
60
|
- [Quick Start](#quick-start)
|
|
61
61
|
- [Install](#install)
|
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
import io
|
|
3
|
-
import mimetypes
|
|
4
|
-
import os
|
|
5
|
-
import re
|
|
6
|
-
import secrets
|
|
7
|
-
import string
|
|
8
|
-
import sys
|
|
9
|
-
from importlib.metadata import version
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
from typing import IO, Any, Dict, List, Optional, TextIO
|
|
12
|
-
|
|
13
|
-
import requests
|
|
14
|
-
from decouple import config
|
|
15
|
-
from dotenv import find_dotenv, load_dotenv
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class ZipURL(object):
|
|
19
|
-
"""
|
|
20
|
-
Zipline URL Object
|
|
21
|
-
:param file_url: Zipline File Display URL
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
__slots__ = ["url", "raw"]
|
|
25
|
-
|
|
26
|
-
def __init__(self, file_url: str):
|
|
27
|
-
self.url: str = file_url
|
|
28
|
-
self.raw: str = self._get_raw(file_url)
|
|
29
|
-
|
|
30
|
-
def __repr__(self):
|
|
31
|
-
return f"<url={self.url} raw={self.raw}>"
|
|
32
|
-
|
|
33
|
-
def __str__(self):
|
|
34
|
-
return self.url
|
|
35
|
-
|
|
36
|
-
@staticmethod
|
|
37
|
-
def _get_raw(url: str) -> str:
|
|
38
|
-
try:
|
|
39
|
-
s = url.split("/", 4)
|
|
40
|
-
return f"{s[0]}//{s[2]}/r/{s[4]}"
|
|
41
|
-
except Exception: # noqa
|
|
42
|
-
return ""
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class Zipline(object):
|
|
46
|
-
"""
|
|
47
|
-
Zipline Python API
|
|
48
|
-
:param base_url: Zipline URL
|
|
49
|
-
:param kwargs: Zipline Headers
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
# noinspection SpellCheckingInspection
|
|
53
|
-
allowed_headers = [
|
|
54
|
-
# zipline v3
|
|
55
|
-
"format",
|
|
56
|
-
"image_compression_percent",
|
|
57
|
-
"expires_at",
|
|
58
|
-
"password",
|
|
59
|
-
"zws",
|
|
60
|
-
"embed",
|
|
61
|
-
"max_views",
|
|
62
|
-
"uploadtext",
|
|
63
|
-
"authorization",
|
|
64
|
-
"no_json",
|
|
65
|
-
"x_zipline_filename",
|
|
66
|
-
"original_name",
|
|
67
|
-
"override_domain",
|
|
68
|
-
# zipline v4
|
|
69
|
-
"x-zipline-deletes-at",
|
|
70
|
-
"x-zipline-format",
|
|
71
|
-
"x-zipline-image-compression-percent",
|
|
72
|
-
"x-zipline-password",
|
|
73
|
-
"x-zipline-max-views",
|
|
74
|
-
"x-zipline-no-json",
|
|
75
|
-
"x-zipline-original-name",
|
|
76
|
-
"x-zipline-folder",
|
|
77
|
-
"x-zipline-filename",
|
|
78
|
-
"x-zipline-domain",
|
|
79
|
-
"x-zipline-file-extension",
|
|
80
|
-
]
|
|
81
|
-
|
|
82
|
-
def __init__(self, url: str, **kwargs):
|
|
83
|
-
self.base_url: str = url.rstrip("/")
|
|
84
|
-
self._headers: Dict[str, str] = {}
|
|
85
|
-
for header, value in kwargs.items():
|
|
86
|
-
if header.lower() not in self.allowed_headers:
|
|
87
|
-
continue
|
|
88
|
-
if value is None:
|
|
89
|
-
continue
|
|
90
|
-
key = header.replace("_", "-").title()
|
|
91
|
-
self._headers[key] = str(value)
|
|
92
|
-
|
|
93
|
-
def send_file(self, file_name: str, file_object: IO, overrides: Optional[dict] = None) -> ZipURL:
|
|
94
|
-
"""
|
|
95
|
-
Upload File to Zipline
|
|
96
|
-
:param file_name: Name of File for files tuple
|
|
97
|
-
:param file_object: File to Upload
|
|
98
|
-
:param overrides: Header Overrides
|
|
99
|
-
:return: File URL
|
|
100
|
-
"""
|
|
101
|
-
url = self.base_url + "/api/upload"
|
|
102
|
-
|
|
103
|
-
path = Path(file_name)
|
|
104
|
-
if not path.is_file():
|
|
105
|
-
raise ValueError(f"Not a File: {path.resolve()}")
|
|
106
|
-
|
|
107
|
-
mime_type = get_type(path)
|
|
108
|
-
# print(f"mime_type: {mime_type}")
|
|
109
|
-
files = {"file": (file_name, file_object, mime_type)}
|
|
110
|
-
headers = self._headers | overrides if overrides else self._headers
|
|
111
|
-
r = requests.post(url, headers=headers, files=files) # nosec
|
|
112
|
-
r.raise_for_status()
|
|
113
|
-
data = r.json()["files"][0]
|
|
114
|
-
if isinstance(data, dict):
|
|
115
|
-
return ZipURL(data["url"])
|
|
116
|
-
elif isinstance(data, list):
|
|
117
|
-
return ZipURL(data[0])
|
|
118
|
-
else:
|
|
119
|
-
return ZipURL(data)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def get_type(file_path: Path) -> str:
|
|
123
|
-
# Deprecated since version 3.13: Passing a file path instead of URL is soft deprecated. Use guess_file_type() for this.
|
|
124
|
-
# https://docs.python.org/3/library/mimetypes.html#mimetypes.guess_type
|
|
125
|
-
mime_type, _ = mimetypes.guess_type(file_path, strict=False)
|
|
126
|
-
if mime_type:
|
|
127
|
-
return mime_type
|
|
128
|
-
return magic_type(file_path)
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
def magic_type(file_path: Path) -> str: # NOSONAR
|
|
132
|
-
try:
|
|
133
|
-
with open(file_path, "rb") as file:
|
|
134
|
-
chunk = file.read(512)
|
|
135
|
-
# print(chunk)
|
|
136
|
-
if chunk[0:3] == b"\xff\xd8\xff" or chunk[6:10] in (b"JFIF", b"Exif"):
|
|
137
|
-
return "image/jpeg"
|
|
138
|
-
elif chunk.startswith(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"):
|
|
139
|
-
return "image/png"
|
|
140
|
-
elif chunk.startswith(b"RIFF") and chunk[8:12] == b"WEBP":
|
|
141
|
-
return "image/webp"
|
|
142
|
-
elif chunk.startswith((b"\x47\x49\x46\x38\x37\x61", b"\x47\x49\x46\x38\x39\x61")):
|
|
143
|
-
return "image/gif"
|
|
144
|
-
elif chunk.startswith(b"\x66\x74\x79\x70\x68\x65\x69\x63\x66\x74\79\70\6d"):
|
|
145
|
-
return "image/heic"
|
|
146
|
-
elif chunk.startswith(b"\x00\x00\x01\x00"):
|
|
147
|
-
return "image/ico"
|
|
148
|
-
|
|
149
|
-
elif chunk[3:11] in (b"\x66\x74\x79\x70\x4d\x53\x4e\x56", b"\x66\x74\x79\x70\x69\x73\x6f\x6d"):
|
|
150
|
-
return "video/mp4"
|
|
151
|
-
elif chunk[4:12] == b"ftypisom" or chunk[4:12] == b"ftypMSNV" or chunk[4:12] == b"ftypmp42":
|
|
152
|
-
return "video/mp4"
|
|
153
|
-
elif chunk.startswith(b"\x1a\x45\xdf\xa3"):
|
|
154
|
-
return "video/x-matroska"
|
|
155
|
-
elif chunk.startswith(b"\x6d\x6f\x6f\x76"):
|
|
156
|
-
return "video/quicktime"
|
|
157
|
-
|
|
158
|
-
elif chunk.startswith((b"\xff\xfb", b"\xff\xfb", b"\xff\xfb", b"\x49\x44\x33")):
|
|
159
|
-
return "audio/mp3"
|
|
160
|
-
elif chunk.startswith(b"RIFF") and chunk[8:12] == b"WAVE":
|
|
161
|
-
return "audio/wav"
|
|
162
|
-
elif chunk.startswith(b"OggS"):
|
|
163
|
-
return "application/ogg"
|
|
164
|
-
|
|
165
|
-
chunk.decode("utf-8")
|
|
166
|
-
return "text/plain"
|
|
167
|
-
except UnicodeDecodeError:
|
|
168
|
-
return "application/octet-stream"
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def format_output(filename: str, url: ZipURL) -> str:
|
|
172
|
-
"""
|
|
173
|
-
Format URL Output
|
|
174
|
-
:param filename: Original or File Name
|
|
175
|
-
:param url: ZipURL to Format
|
|
176
|
-
:return: Formatted Output
|
|
177
|
-
"""
|
|
178
|
-
zipline_format = config("ZIPLINE_FORMAT", "{filename}\n{url}\n{raw_url}")
|
|
179
|
-
return zipline_format.format(filename=filename, url=url, raw_url=url.raw)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
def gen_rand(length: int = 4) -> str:
|
|
183
|
-
"""
|
|
184
|
-
Generate Random Streng
|
|
185
|
-
:param length: Length of String
|
|
186
|
-
:return: Random String
|
|
187
|
-
"""
|
|
188
|
-
r = "".join(secrets.choice(string.ascii_letters) for _ in range(length))
|
|
189
|
-
return "".join(r)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def get_default(
|
|
193
|
-
values: List[str],
|
|
194
|
-
default: Optional[Any] = None,
|
|
195
|
-
cast: type = str,
|
|
196
|
-
pre: str = "ZIPLINE_",
|
|
197
|
-
suf: str = "",
|
|
198
|
-
) -> Optional[str]:
|
|
199
|
-
"""
|
|
200
|
-
Get Default Environment Variable from List of values
|
|
201
|
-
:param values: List of Values to Check
|
|
202
|
-
:param default: Default Value if None
|
|
203
|
-
:param cast: Type to Cast Value
|
|
204
|
-
:param pre: Environment Variable Prefix
|
|
205
|
-
:param suf: Environment Variable Suffix
|
|
206
|
-
:return: Environment Variable or None
|
|
207
|
-
"""
|
|
208
|
-
for value in values:
|
|
209
|
-
result = config(f"{pre}{value.upper()}{suf}", "", cast)
|
|
210
|
-
if result:
|
|
211
|
-
return result
|
|
212
|
-
return default
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
def setup(env_file: Path) -> None:
|
|
216
|
-
print("Setting up Environment File...")
|
|
217
|
-
url = input("Zipline URL: ").strip()
|
|
218
|
-
token = input("Zipline Authorization Token: ").strip()
|
|
219
|
-
if not url or not token:
|
|
220
|
-
raise ValueError("Missing URL or Token.")
|
|
221
|
-
output = f"ZIPLINE_URL={url}\nZIPLINE_TOKEN={token}\n"
|
|
222
|
-
embed = input("Enabled Embed? [Yes]/No: ").strip()
|
|
223
|
-
if not embed or embed.lower() not in ["n", "o", "no", "noo"]:
|
|
224
|
-
output += "ZIPLINE_EMBED=true\n"
|
|
225
|
-
expire = input("Default Expire? [Blank for None]: ").strip().lower()
|
|
226
|
-
if expire:
|
|
227
|
-
match = re.search(r"^(\d+)(?:ms|s|m|h|d|w|y)$", expire)
|
|
228
|
-
if not match:
|
|
229
|
-
print(f"Warning: invalid expire format: {expire}. See --help")
|
|
230
|
-
else:
|
|
231
|
-
output += f"ZIPLINE_EXPIRE={expire}\n"
|
|
232
|
-
with open(env_file, "w") as f:
|
|
233
|
-
f.write(output)
|
|
234
|
-
print(f"Setup Complete. Variables Saved to: {env_file}")
|
|
235
|
-
sys.exit(0)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
def run() -> None:
|
|
239
|
-
zipline_file = ".zipline"
|
|
240
|
-
env_file = Path(os.path.expanduser("~")) / zipline_file
|
|
241
|
-
dotenv_path = env_file if os.path.isfile(env_file) else find_dotenv(filename=zipline_file)
|
|
242
|
-
env = load_dotenv(dotenv_path=dotenv_path)
|
|
243
|
-
|
|
244
|
-
parser = argparse.ArgumentParser(description="Zipline CLI.")
|
|
245
|
-
parser.add_argument("files", metavar="Files", type=str, nargs="*", help="Files to Upload.")
|
|
246
|
-
parser.add_argument("-s", "--setup", action="store_true", default=False, help="run the interactive setup")
|
|
247
|
-
parser.add_argument("-i", "--info", action="store_true", help="show application information")
|
|
248
|
-
parser.add_argument("-V", "--version", action="store_true", help="show the installed version")
|
|
249
|
-
parser.add_argument("-u", "--url", type=str, default=get_default(["url"]), help="Zipline URL")
|
|
250
|
-
parser.add_argument(
|
|
251
|
-
"-a",
|
|
252
|
-
"-t",
|
|
253
|
-
"--authorization",
|
|
254
|
-
"--token",
|
|
255
|
-
type=str,
|
|
256
|
-
default=get_default(["token", "authorization"]),
|
|
257
|
-
help="Zipline Access Token for Authorization or ZIPLINE_TOKEN",
|
|
258
|
-
)
|
|
259
|
-
parser.add_argument(
|
|
260
|
-
"-e",
|
|
261
|
-
"-x",
|
|
262
|
-
"--expires_at",
|
|
263
|
-
"--expire",
|
|
264
|
-
type=str,
|
|
265
|
-
default=get_default(["expire", "expire_at"]),
|
|
266
|
-
help="Ex: 1d, 2w. See: https://zipline.diced.sh/docs/guides/upload-options#image-expiration",
|
|
267
|
-
)
|
|
268
|
-
parser.add_argument(
|
|
269
|
-
"--embed", action="store_true", default=get_default(["embed"], False, bool), help="Enable Embeds on Uploads."
|
|
270
|
-
)
|
|
271
|
-
args = parser.parse_args()
|
|
272
|
-
|
|
273
|
-
if args.version:
|
|
274
|
-
print(version("zipline-cli"))
|
|
275
|
-
return
|
|
276
|
-
|
|
277
|
-
if args.info:
|
|
278
|
-
print(f"Zipline Version: {version('zipline-cli')}")
|
|
279
|
-
print(f"Config File: {env_file.absolute()}")
|
|
280
|
-
print(f"Server URL: {config('ZIPLINE_URL', '')}")
|
|
281
|
-
print(f"Token (ends in): {config('ZIPLINE_TOKEN', '')[-10:]}")
|
|
282
|
-
print(f"Expire: {config('ZIPLINE_EXPIRE', '')}")
|
|
283
|
-
print(f"Embed: {config('ZIPLINE_EMBED', '')}")
|
|
284
|
-
zipline_format = config("ZIPLINE_FORMAT", "{url}\n{raw_url}")
|
|
285
|
-
print(f"URL Format::\n{zipline_format}")
|
|
286
|
-
return
|
|
287
|
-
|
|
288
|
-
if args.setup:
|
|
289
|
-
setup(env_file)
|
|
290
|
-
|
|
291
|
-
if not env and not args.url and not args.authorization and not os.path.isfile(env_file):
|
|
292
|
-
env_file.touch()
|
|
293
|
-
print("First Run Detected, Entering Setup.")
|
|
294
|
-
setup(env_file)
|
|
295
|
-
|
|
296
|
-
if not args.url:
|
|
297
|
-
parser.print_help()
|
|
298
|
-
raise ValueError("Missing URL. Use --setup or specify --url")
|
|
299
|
-
|
|
300
|
-
if not args.authorization:
|
|
301
|
-
parser.print_help()
|
|
302
|
-
raise ValueError("Missing Token. Use --setup or specify --token")
|
|
303
|
-
|
|
304
|
-
if args.expires_at:
|
|
305
|
-
args.expires_at = args.expires_at.strip().lower()
|
|
306
|
-
match = re.search(r"^(\d+)(?:ms|s|m|h|d|w|y)$", args.expires_at)
|
|
307
|
-
if not match:
|
|
308
|
-
parser.print_help()
|
|
309
|
-
raise ValueError(f"Invalid Expire Format: {args.expires_at}.")
|
|
310
|
-
|
|
311
|
-
zipline = Zipline(**vars(args))
|
|
312
|
-
|
|
313
|
-
if not args.files:
|
|
314
|
-
content: str = sys.stdin.read().rstrip("\n") + "\n"
|
|
315
|
-
text_f: TextIO = io.StringIO(content)
|
|
316
|
-
name = f"{gen_rand(8)}.txt"
|
|
317
|
-
url: ZipURL = zipline.send_file(name, text_f)
|
|
318
|
-
print(format_output(name, url))
|
|
319
|
-
sys.exit(0)
|
|
320
|
-
|
|
321
|
-
exit_code = 1
|
|
322
|
-
for name in args.files:
|
|
323
|
-
if not os.path.isfile(name):
|
|
324
|
-
print(f"Warning: File Not Found: {name}")
|
|
325
|
-
continue
|
|
326
|
-
# mode: Literal["r", "rb"] = get_mode(name)
|
|
327
|
-
with open(name, "rb") as f:
|
|
328
|
-
# name, ext = os.path.splitext(os.path.basename(filename))
|
|
329
|
-
# ext = f'.{ext}' if ext else ''
|
|
330
|
-
# name = f'{name}-{gen_rand(8)}{ext}'
|
|
331
|
-
# url: str = zipline.send_file(name, f)
|
|
332
|
-
zip_url: ZipURL = zipline.send_file(name, f)
|
|
333
|
-
print(format_output(name, zip_url))
|
|
334
|
-
exit_code = 0
|
|
335
|
-
sys.exit(exit_code)
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
def main() -> None:
|
|
339
|
-
try:
|
|
340
|
-
run()
|
|
341
|
-
except KeyboardInterrupt:
|
|
342
|
-
sys.exit(1)
|
|
343
|
-
except Exception as error:
|
|
344
|
-
print("\nError: {}".format(str(error)))
|
|
345
|
-
sys.exit(1)
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
if __name__ == "__main__":
|
|
349
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|