tempspace-cli 1.1.1__tar.gz → 1.2.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tempspace-cli
3
- Version: 1.1.1
3
+ Version: 1.2.0
4
4
  Summary: A command-line tool for uploading files to Tempspace.
5
5
  Author-email: Tempspace <mcbplay1@gmail.com>
6
6
  License: MIT License
@@ -9,7 +9,6 @@ Classifier: Operating System :: OS Independent
9
9
  Requires-Python: >=3.7
10
10
  Description-Content-Type: text/markdown
11
11
  Requires-Dist: requests==2.31.0
12
- Requires-Dist: tqdm==4.66.1
13
12
  Requires-Dist: requests-toolbelt==1.0.0
14
13
  Requires-Dist: rich==13.7.1
15
14
  Requires-Dist: qrcode==8.2
@@ -4,7 +4,6 @@ import os
4
4
  import sys
5
5
  import hashlib
6
6
  import multiprocessing
7
- from tqdm import tqdm
8
7
  from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncoderMonitor
9
8
  import math
10
9
  from rich.console import Console
@@ -13,6 +12,9 @@ from rich.table import Table
13
12
  from rich import box
14
13
  import qrcode
15
14
  from rich.prompt import Prompt, Confirm
15
+ from rich.progress import Progress, BarColumn, TextColumn, TransferSpeedColumn, TimeRemainingColumn
16
+ from rich.console import Group
17
+ from rich.live import Live
16
18
 
17
19
  # Default configuration
18
20
  DEFAULT_SERVER_URL = "https://tempspace.fly.dev/"
@@ -41,18 +43,6 @@ def parse_time(time_str: str) -> int:
41
43
  except ValueError:
42
44
  return None
43
45
 
44
- def calculate_file_hash(filepath: str) -> str:
45
- """Calculate the SHA256 hash of a file in chunks."""
46
- sha256_hash = hashlib.sha256()
47
- try:
48
- with open(filepath, "rb") as f:
49
- for byte_block in iter(lambda: f.read(CHUNK_SIZE), b""):
50
- sha256_hash.update(byte_block)
51
- return sha256_hash.hexdigest()
52
- except IOError as e:
53
- print(f"Error reading file for hashing: {e}", file=sys.stderr)
54
- sys.exit(1)
55
-
56
46
  def format_size(size_bytes: int) -> str:
57
47
  """Converts a size in bytes to a human-readable format."""
58
48
  if size_bytes == 0:
@@ -117,47 +107,77 @@ def main():
117
107
  console.print(table)
118
108
 
119
109
 
120
- # --- Hashing ---
121
- console.print("[cyan]Calculating file hash...[/]")
122
- client_hash = calculate_file_hash(args.filepath)
123
- console.print(f" [cyan]- Hash:[/] {client_hash}")
124
-
125
110
  # --- Prepare Upload ---
126
- upload_url = f"{args.url.rstrip('/')}/upload"
111
+ upload_url = f"{args.url.rstrip('/')}"
127
112
  filename = os.path.basename(args.filepath)
128
113
  file_size = os.path.getsize(args.filepath)
129
114
 
130
- fields = {
131
- 'hours': str(hours),
132
- 'one_time': str(args.one_time).lower(),
133
- 'client_hash': client_hash,
134
- 'file': (filename, open(args.filepath, 'rb'), 'application/octet-stream')
135
- }
136
- if args.password:
137
- fields['password'] = args.password
138
-
139
- encoder = MultipartEncoder(fields=fields)
115
+ # --- Chunked Upload ---
140
116
  response = None
141
-
142
117
  try:
143
- bar_format = "{desc}: {percentage:3.0f}%|{bar}| {n_fmt}/{total_fmt} [Speed: {rate_fmt}, ETA: {remaining}]"
144
- with tqdm(total=encoder.len, unit='B', unit_scale=True, desc=f"Uploading {filename}", bar_format=bar_format) as pbar:
145
- monitor = MultipartEncoderMonitor(encoder, lambda m: pbar.update(m.bytes_read - pbar.n))
146
- response = requests.post(upload_url, data=monitor, headers={'Content-Type': monitor.content_type})
118
+ # 1. Initiate Upload
119
+ initiate_response = requests.post(f"{upload_url}/upload/initiate")
120
+ initiate_response.raise_for_status()
121
+ upload_id = initiate_response.json()['upload_id']
122
+
123
+ # 2. Upload Chunks
124
+ progress = Progress(
125
+ TextColumn("[bold blue]{task.description}", justify="right"),
126
+ BarColumn(bar_width=None),
127
+ "[progress.percentage]{task.percentage:>3.1f}%", "•",
128
+ TransferSpeedColumn(), "•",
129
+ TimeRemainingColumn(),
130
+ )
131
+
132
+ with Live(Panel(progress, title="[cyan]Uploading[/cyan]", border_style="cyan", title_align="left")) as live:
133
+ task_id = progress.add_task(filename, total=file_size)
134
+ with open(args.filepath, 'rb') as f:
135
+ chunk_number = 0
136
+ while chunk := f.read(CHUNK_SIZE):
137
+ chunk_number += 1
138
+ chunk_data = {
139
+ 'upload_id': upload_id,
140
+ 'chunk_number': str(chunk_number)
141
+ }
142
+ files = {'file': (f'chunk_{chunk_number}', chunk, 'application/octet-stream')}
143
+
144
+ chunk_response = requests.post(
145
+ f"{upload_url}/upload/chunk",
146
+ data=chunk_data,
147
+ files=files
148
+ )
149
+ chunk_response.raise_for_status()
150
+ progress.update(task_id, advance=len(chunk))
151
+
152
+ # 3. Finalize Upload
153
+ console.print(Panel("[bold green]Finalizing upload...[/bold green]", border_style="green"))
154
+ finalize_data = {
155
+ 'upload_id': upload_id,
156
+ 'filename': filename,
157
+ 'hours': str(hours),
158
+ 'one_time': str(args.one_time).lower(),
159
+ }
160
+ if args.password:
161
+ finalize_data['password'] = args.password
162
+
163
+ response = requests.post(f"{upload_url}/upload/finalize", data=finalize_data)
164
+ response.raise_for_status()
147
165
 
148
166
  except FileNotFoundError:
149
167
  console.print(Panel(f"[bold red]Error:[/] The file '{args.filepath}' was not found.", title="[bold red]Error[/bold red]", border_style="red"))
150
168
  sys.exit(1)
151
169
  except requests.exceptions.RequestException as e:
152
- console.print(Panel(f"[bold red]An error occurred while connecting to the server:[/]\n{e}", title="[bold red]Error[/bold red]", border_style="red"))
170
+ error_message = str(e)
171
+ if e.response:
172
+ try:
173
+ error_message = e.response.json().get('detail', e.response.text)
174
+ except:
175
+ error_message = e.response.text
176
+ console.print(Panel(f"[bold red]An error occurred:[/] {error_message}", title="[bold red]Error[/bold red]", border_style="red"))
153
177
  sys.exit(1)
154
178
  except Exception as e:
155
179
  console.print(Panel(f"[bold red]An unexpected error occurred:[/] {e}", title="[bold red]Error[/bold red]", border_style="red"))
156
180
  sys.exit(1)
157
- finally:
158
- # Ensure the file handle is closed
159
- if 'file' in fields and not fields['file'][1].closed:
160
- fields['file'][1].close()
161
181
 
162
182
  # --- Handle Response ---
163
183
  if response is not None:
@@ -7,7 +7,7 @@ packages = ["cli"]
7
7
 
8
8
  [project]
9
9
  name = "tempspace-cli"
10
- version = "1.1.1"
10
+ version = "1.2.0"
11
11
  authors = [
12
12
  { name="Tempspace", email="mcbplay1@gmail.com" },
13
13
  ]
@@ -21,7 +21,6 @@ classifiers = [
21
21
  ]
22
22
  dependencies = [
23
23
  "requests==2.31.0",
24
- "tqdm==4.66.1",
25
24
  "requests-toolbelt==1.0.0",
26
25
  "rich==13.7.1",
27
26
  "qrcode==8.2",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tempspace-cli
3
- Version: 1.1.1
3
+ Version: 1.2.0
4
4
  Summary: A command-line tool for uploading files to Tempspace.
5
5
  Author-email: Tempspace <mcbplay1@gmail.com>
6
6
  License: MIT License
@@ -9,7 +9,6 @@ Classifier: Operating System :: OS Independent
9
9
  Requires-Python: >=3.7
10
10
  Description-Content-Type: text/markdown
11
11
  Requires-Dist: requests==2.31.0
12
- Requires-Dist: tqdm==4.66.1
13
12
  Requires-Dist: requests-toolbelt==1.0.0
14
13
  Requires-Dist: rich==13.7.1
15
14
  Requires-Dist: qrcode==8.2
@@ -1,5 +1,4 @@
1
1
  requests==2.31.0
2
- tqdm==4.66.1
3
2
  requests-toolbelt==1.0.0
4
3
  rich==13.7.1
5
4
  qrcode==8.2
File without changes
File without changes