| Hash | Commit message | Author | Date | Files | + | - |
1 | commit cc55e9e86f3475baffaab759f44808cd85962c3d |
2 | Author: Connor Etherington <[email protected]> |
3 | Date: Fri Aug 4 06:32:27 2023 +0200 |
4 | |
5 | Auto-Commit Update - 20230804 |
6 | --- |
7 | .gitignore | 3 + |
8 | PKGBUILD | 2 +- |
9 | README.md | 36 +++++--- |
10 | build/lib/ptrack/__init__.py | 16 ---- |
11 | build/lib/ptrack/main.py | 134 ---------------------------- |
12 | build/lib/ptrack/methods.py | 94 ------------------- |
13 | dist/ptrack-0.1.4-py3-none-any.whl | Bin 5267 -> 0 bytes |
14 | dist/ptrack-0.1.4.tar.gz | Bin 4096 -> 0 bytes |
15 | ptrack.egg-info/PKG-INFO | 7 -- |
16 | ptrack.egg-info/SOURCES.txt | 12 --- |
17 | ptrack.egg-info/dependency_links.txt | 1 - |
18 | ptrack.egg-info/entry_points.txt | 4 - |
19 | ptrack.egg-info/requires.txt | 3 - |
20 | ptrack.egg-info/top_level.txt | 1 - |
21 | ptrack/__init__.py | 4 +- |
22 | ptrack/__pycache__/__init__.cpython-310.pyc | Bin 799 -> 0 bytes |
23 | ptrack/__pycache__/main.cpython-310.pyc | Bin 3732 -> 0 bytes |
24 | ptrack/__pycache__/methods.cpython-310.pyc | Bin 2831 -> 0 bytes |
25 | ptrack/download.py | 15 ++++ |
26 | ptrack/main.py | 70 ++++++++++++++- |
27 | ptrack/methods.py | 54 +++++++++-- |
28 | setup.py | 8 +- |
29 | 22 files changed, 167 insertions(+), 297 deletions(-) |
30 | |
31 | diff --git a/.gitignore b/.gitignore |
32 | index d7f7a42..f58297f 100644 |
33 | --- a/.gitignore |
34 | +++ b/.gitignore |
35 | @@ -1 +1,4 @@ |
36 | .mypy_cache |
37 | +__pycache__ |
38 | +ptrack/.mypy_cache |
39 | +ptrack/__pycache__ |
40 | diff --git a/PKGBUILD b/PKGBUILD |
41 | index c8e5899..f6154f2 100644 |
42 | --- a/PKGBUILD |
43 | +++ b/PKGBUILD |
44 | @@ -1,7 +1,7 @@ |
45 | # Maintainer: Connor Etherington <[email protected]> |
46 | # --- |
47 | pkgname=ptrack |
48 | -pkgver=0.1.4 |
49 | +pkgver=0.2.1 |
50 | pkgrel=1 |
51 | pkgdesc="A simple CLI utility for asthetically tracking progress when copying or moving files" |
52 | arch=(x86_64) |
53 | diff --git a/README.md b/README.md |
54 | index dc1cb89..43cfe50 100644 |
55 | --- a/README.md |
56 | +++ b/README.md |
57 | @@ -1,9 +1,9 @@ |
58 | # P-Track - Progress Tracker |
59 | |
60 | -### Welcome to ptrack, a powerful and user-friendly command line interface (CLI) utility built to transform the way you handle file operations. Whether you're copying or moving files, ptrack provides a real-time, beautifully formatted progress bar alongside key statistics about your ongoing operation. |
61 | -### As an incredibly efficient and performance-optimized tool, ptrack works swiftly, ensuring your file operations are completed accurately and quickly. |
62 | +### Welcome to ptrack, a powerful and user-friendly CLI utility for tracking the progress of your file operations. |
63 | +### Designed to be as concise, efficient and performance-optimized, ptrack works swiftly and accurately, while providing insight into the progress of the task at hand. |
64 | |
65 | -*Version: 0.1.4* |
66 | +*Version: 0.2.1* |
67 | |
68 | *** |
69 | |
70 | @@ -13,9 +13,11 @@ |
71 | |
72 | + Progress Bar: ptrack comes equipped with an aesthetically pleasing progress bar that updates in real-time, giving you a visual representation of your ongoing file operation. |
73 | + Verbose Mode: If you prefer a more in-depth perspective, ptrack has a verbose mode which displays detailed information about each file being processed. |
74 | -+ Copy and Move Support: Whether you need to copy or move files, ptrack has you covered. You can use ptrack with -c for copy operations and -m for move operations. |
75 | ++ Copying and Moving Files: ptrack supports both copying and moving files on any unix-like opperating system, including Linux, macOS, and BSD. |
76 | ++ Downloading Files: ptrack can be used to download files from specified URLs. It will display the progress of the download in real-time, and will also display the download speed. |
77 | + Interruption Handling: ptrack is built to respect your system's interruption signals. It will promptly stop operations when such signals are received, reducing the risk of data corruption. |
78 | + High Performance: Above all, ptrack stands out for its speed and accuracy. It ensures your file operations are executed swiftly and with a high degree of precision. |
79 | ++ |
80 | |
81 | |
82 | ## Installation: |
83 | @@ -44,23 +46,31 @@ |
84 | |
85 | The basic usage of ptrack isvery simple: |
86 | |
87 | +`ptrack [-h] [-v] [-c] [-m] [-d] [-V] [SOURCE...] [DESTINATION]` |
88 | + |
89 | ```bash |
90 | -### For Copying |
91 | - ptc [OPTIONS] SOURCE... DESTINATION |
92 | |
93 | -### For Moving |
94 | - ptm [OPTIONS] SOURCE... DESTINATION |
95 | +### Copying Files |
96 | + ptc [OPTIONS] SOURCE... DESTINATION ( or ptrack -c SOURCE... DESTINATION ) |
97 | + |
98 | +### Moving Files |
99 | + ptm [OPTIONS] SOURCE... DESTINATION ( or ptrack -m SOURCE... DESTINATION ) |
100 | + |
101 | +### Downloading Files |
102 | + ptd [OPTIONS] URL(S) ( or ptrack -d URL(S) ) |
103 | ``` |
104 | |
105 | Refer to the User Guide for more detailed instructions and use-cases. |
106 | |
107 | |
108 | ## Options: |
109 | -+ -h, --help: Show help message and exit. |
110 | -+ -v, --verbose: Enable verbose output. |
111 | -+ -c, --copy: Copy files. You can use ptc instead of ptrack -c. |
112 | -+ -m, --move: Move files. You can use ptm instead of ptrack -m. |
113 | -+ -V, --version: Show version number and exit. |
114 | + |
115 | +* -h, --help show this help message and exit |
116 | +* -v, --verbose verbose output |
117 | +* -c, --copy copy files (You can use `ptc` instead of `ptrack -c`) |
118 | +* -m, --move move files (You can use `ptm` instead of `ptrack -m`) |
119 | +* -d, --download download files (You can use `ptd` instead of `ptrack -d`) |
120 | +* -V, --version show program's version number and exit |
121 | |
122 | |
123 | ![Regular Copy](./.gitlab/media/copy.gif) |
124 | diff --git a/build/lib/ptrack/__init__.py b/build/lib/ptrack/__init__.py |
125 | deleted file mode 100644 |
126 | index 57693c9..0000000 |
127 | --- a/build/lib/ptrack/__init__.py |
128 | +++ /dev/null |
129 | @@ -1,16 +0,0 @@ |
130 | -import argparse |
131 | -import argcomplete |
132 | -version="0.1.4" |
133 | - |
134 | -parser = argparse.ArgumentParser(description='A simple CLI utility for asthetically tracking progress when copying or moving files.') |
135 | -parser.add_argument('-v', '--verbose', action='store_true', help='verbose output') |
136 | -parser.add_argument('-c', '--copy', action='store_true', help='copy files (You can use `ptc` instead of `ptrack -c`)') |
137 | -parser.add_argument('-m', '--move', action='store_true', help='move files (You can use `ptm` instead of `ptrack -m`)') |
138 | -parser.add_argument('-V', '--version', action='version', version='%(prog)s' + version) |
139 | - |
140 | -argcomplete.autocomplete(parser) |
141 | -args, unknown = parser.parse_known_args() |
142 | - |
143 | -verbose = args.verbose |
144 | -copy = args.copy |
145 | -move = args.move |
146 | diff --git a/build/lib/ptrack/main.py b/build/lib/ptrack/main.py |
147 | deleted file mode 100644 |
148 | index cc43997..0000000 |
149 | --- a/build/lib/ptrack/main.py |
150 | +++ /dev/null |
151 | @@ -1,134 +0,0 @@ |
152 | -import os |
153 | -import sys |
154 | -import ptrack |
155 | -from ptrack.methods import format_file_size, regular_copy, verbose_copy, hlp, getTotalSize |
156 | -from rich.progress import Progress, BarColumn, TextColumn, TimeRemainingColumn, FileSizeColumn |
157 | -from rich.console import Console |
158 | -import shutil |
159 | - |
160 | -verbose = ptrack.verbose |
161 | -argCopy = ptrack.copy |
162 | -argMove = ptrack.move |
163 | - |
164 | - |
165 | -def run(process): |
166 | - console = Console() |
167 | - |
168 | - if len(sys.argv) < 3: |
169 | - hlp() |
170 | - if process == "Copying": |
171 | - console.print("[bold cyan]Usage: ptc [OPTIONS] SOURCE... DESTINATION[/bold cyan]") |
172 | - elif process == "Moving": |
173 | - console.print("[bold cyan]Usage: ptm [OPTIONS] SOURCE... DESTINATION[/bold cyan]") |
174 | - sys.exit(1) |
175 | - |
176 | - src_paths = sys.argv[1:-1] |
177 | - dst = sys.argv[-1] |
178 | - srcPaths = [] |
179 | - |
180 | - for path in src_paths: |
181 | - if path.endswith('/'): |
182 | - path = path[:-1] |
183 | - srcPaths.append(path) |
184 | - |
185 | - if os.path.isdir(dst): |
186 | - dst_dir = dst |
187 | - new_name = None |
188 | - else: |
189 | - dst_dir = os.path.dirname(dst) |
190 | - new_name = os.path.basename(dst) |
191 | - |
192 | - total_files = sum(len(files) for path in srcPaths for r, d, files in os.walk(path) if os.path.isdir(path)) + sum(1 for path in srcPaths if os.path.isfile(path)) |
193 | - total_size = getTotalSize(srcPaths) |
194 | - |
195 | - current_file = 1 |
196 | - |
197 | - if total_files > 1: |
198 | - console.print(f"\n[#ea2a6f]{process}:[/#ea2a6f] [bold cyan]{total_files} files[/bold cyan]\n") |
199 | - else: |
200 | - for src_path in srcPaths: |
201 | - if os.path.isfile(src_path): |
202 | - console.print(f"\n[#ea2a6f]{process}:[/#ea2a6f] [bold cyan] {os.path.basename(src_path)} [/bold cyan]\n") |
203 | - |
204 | - if verbose: |
205 | - for src_path in srcPaths: |
206 | - if os.path.isfile(src_path): |
207 | - dst_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name) |
208 | - terminate = verbose_copy(src_path, dst_path, console, current_file, total_files) |
209 | - current_file += 1 |
210 | - if terminate == 'c': |
211 | - console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
212 | - sys.exit(1) |
213 | - else: |
214 | - for root, dirs, files in os.walk(src_path): |
215 | - for file in files: |
216 | - src_file_path = os.path.join(root, file) |
217 | - relative_path = os.path.relpath(src_file_path, start=src_path) |
218 | - dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name, relative_path) |
219 | - os.makedirs(os.path.dirname(dst_file_path), exist_ok=True) |
220 | - terminate = verbose_copy(src_file_path, dst_file_path, console, current_file, total_files) |
221 | - current_file += 1 |
222 | - if terminate == 'c': |
223 | - console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
224 | - sys.exit(1) |
225 | - else: |
226 | - with Progress( |
227 | - BarColumn(bar_width=50), |
228 | - "[progress.percentage]{task.percentage:>3.0f}%", |
229 | - TimeRemainingColumn(), |
230 | - "[#ea2a6f][[/#ea2a6f]", |
231 | - FileSizeColumn(), |
232 | - "[#ea2a6f]/[/#ea2a6f]", |
233 | - TextColumn("[bold cyan]{task.fields[total_size]}[/bold cyan]"), |
234 | - "[#ea2a6f]][/#ea2a6f]", |
235 | - console=console, |
236 | - auto_refresh=False |
237 | - ) as progress: |
238 | - task = progress.add_task("", total=total_size, total_size=format_file_size(total_size)) |
239 | - |
240 | - for src_path in srcPaths: |
241 | - if os.path.isfile(src_path): |
242 | - dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name) |
243 | - terminate = regular_copy(src_path, dst_file_path, console, task, progress) |
244 | - if terminate == 'c': |
245 | - console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
246 | - sys.exit(1) |
247 | - else: |
248 | - for root, dirs, files in os.walk(src_path): |
249 | - for file in files: |
250 | - src_file_path = os.path.join(root, file) |
251 | - relative_path = os.path.relpath(src_file_path, start=src_path) |
252 | - dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name, relative_path) |
253 | - os.makedirs(os.path.dirname(dst_file_path), exist_ok=True) |
254 | - terminate = regular_copy(src_file_path, dst_file_path, console, task, progress) |
255 | - if terminate == 'c': |
256 | - console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
257 | - sys.exit(1) |
258 | - |
259 | - return srcPaths |
260 | - |
261 | - |
262 | -def copy(): |
263 | - run('Copying') |
264 | - |
265 | - |
266 | -def move(): |
267 | - src_paths = run('Moving') |
268 | - for src_path in src_paths: |
269 | - if os.path.isfile(src_path): |
270 | - os.remove(src_path) |
271 | - else: |
272 | - shutil.rmtree(src_path) |
273 | - |
274 | - |
275 | -def main(): |
276 | - if argMove: |
277 | - move() |
278 | - elif argCopy: |
279 | - copy() |
280 | - else: |
281 | - hlp() |
282 | - |
283 | - |
284 | -if __name__ == "__main__": |
285 | - main() |
286 | diff --git a/build/lib/ptrack/methods.py b/build/lib/ptrack/methods.py |
287 | deleted file mode 100644 |
288 | index cbe9420..0000000 |
289 | --- a/build/lib/ptrack/methods.py |
290 | +++ /dev/null |
291 | @@ -1,94 +0,0 @@ |
292 | -import os |
293 | -from rich.progress import Progress, BarColumn, TextColumn, TimeRemainingColumn, FileSizeColumn |
294 | - |
295 | - |
296 | -def getTotalSize(srcPaths): |
297 | - total_size = 0 |
298 | - for path in srcPaths: |
299 | - if os.path.isfile(path): |
300 | - total_size += os.path.getsize(path) |
301 | - else: |
302 | - for r, d, files in os.walk(path): |
303 | - for f in files: |
304 | - fp = os.path.join(r, f) |
305 | - total_size += os.path.getsize(fp) |
306 | - return total_size |
307 | - |
308 | - |
309 | -def format_file_size(file_size): |
310 | - if file_size >= 1000 ** 4: # Terabyte |
311 | - return f"{round(file_size / (1000 ** 4))} TB" |
312 | - elif file_size >= 1000 ** 3: # Gigabyte |
313 | - return f"{round(file_size / (1000 ** 3))} GB" |
314 | - elif file_size >= 1000 ** 2: # Megabyte |
315 | - return f"{round(file_size / (1000 ** 2))} MB" |
316 | - elif file_size >= 1000: # Kilobyte |
317 | - return f"{round(file_size / 1000)} kB" |
318 | - else: # Byte |
319 | - return f"{file_size} bytes" |
320 | - |
321 | - |
322 | -def regular_copy(src, dst, console, task, progress): |
323 | - operation_cancelled = False |
324 | - try: |
325 | - with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: |
326 | - while True: |
327 | - buf = fsrc.read(1024*1024) |
328 | - if not buf or operation_cancelled: |
329 | - break |
330 | - fdst.write(buf) |
331 | - progress.update(task, advance=len(buf)) |
332 | - progress.refresh() |
333 | - |
334 | - except KeyboardInterrupt: |
335 | - operation_cancelled = True |
336 | - progress.stop() |
337 | - return "c" |
338 | - |
339 | - |
340 | -def verbose_copy(src, dst, console, current, total_files): |
341 | - operation_cancelled = False |
342 | - file_size = os.path.getsize(src) |
343 | - |
344 | - with Progress( |
345 | - BarColumn(bar_width=50), |
346 | - "[progress.percentage]{task.percentage:>3.0f}%", |
347 | - TimeRemainingColumn(), |
348 | - "[#ea2a6f][[/#ea2a6f]", |
349 | - FileSizeColumn(), |
350 | - "[#ea2a6f]/[/#ea2a6f]", |
351 | - TextColumn(f"[bold cyan]{format_file_size(file_size)}[/bold cyan]"), |
352 | - "[#ea2a6f]][/#ea2a6f]", |
353 | - f"({current} of {total_files})", |
354 | - console=console, |
355 | - auto_refresh=False |
356 | - ) as progress: |
357 | - task = progress.add_task("", total=file_size, file_size=format_file_size(file_size)) |
358 | - |
359 | - try: |
360 | - with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: |
361 | - while not progress.finished: |
362 | - buf = fsrc.read(1024*1024) |
363 | - if not buf or operation_cancelled: |
364 | - break |
365 | - fdst.write(buf) |
366 | - progress.update(task, advance=len(buf)) |
367 | - progress.refresh() |
368 | - except KeyboardInterrupt: |
369 | - operation_cancelled = True |
370 | - progress.stop() |
371 | - return "c" |
372 | - |
373 | - |
374 | -def hlp(): |
375 | - print(""" |
376 | -usage: ptrack [-h] [-v] [-c] [-m] |
377 | - |
378 | -A simple CLI utility for asthetically tracking progress when copying or moving files. |
379 | - |
380 | -options: |
381 | - -h, --help show this help message and exit |
382 | - -v, --verbose verbose output |
383 | - -c, --copy copy files (You can use `ptc` instead of `ptrack -c`) |
384 | - -m, --move move files (You can use `ptm` instead of `ptrack -m`) |
385 | -""") |
386 | diff --git a/dist/ptrack-0.1.4-py3-none-any.whl b/dist/ptrack-0.1.4-py3-none-any.whl |
387 | deleted file mode 100644 |
388 | index 43fa218..0000000 |
389 | Binary files a/dist/ptrack-0.1.4-py3-none-any.whl and /dev/null differ |
390 | diff --git a/dist/ptrack-0.1.4.tar.gz b/dist/ptrack-0.1.4.tar.gz |
391 | deleted file mode 100644 |
392 | index 5363d37..0000000 |
393 | Binary files a/dist/ptrack-0.1.4.tar.gz and /dev/null differ |
394 | diff --git a/ptrack.egg-info/PKG-INFO b/ptrack.egg-info/PKG-INFO |
395 | deleted file mode 100644 |
396 | index f873109..0000000 |
397 | --- a/ptrack.egg-info/PKG-INFO |
398 | +++ /dev/null |
399 | @@ -1,7 +0,0 @@ |
400 | -Metadata-Version: 2.1 |
401 | -Name: ptrack |
402 | -Version: 0.1.4 |
403 | -Summary: A simple CLI utility for asthetically tracking progress when copying or moving files. |
404 | -Author: Connor Etherington |
405 | -Author-email: [email protected] |
406 | -License-File: LICENSE |
407 | diff --git a/ptrack.egg-info/SOURCES.txt b/ptrack.egg-info/SOURCES.txt |
408 | deleted file mode 100644 |
409 | index 086a784..0000000 |
410 | --- a/ptrack.egg-info/SOURCES.txt |
411 | +++ /dev/null |
412 | @@ -1,12 +0,0 @@ |
413 | -LICENSE |
414 | -README.md |
415 | -setup.py |
416 | -ptrack/__init__.py |
417 | -ptrack/main.py |
418 | -ptrack/methods.py |
419 | -ptrack.egg-info/PKG-INFO |
420 | -ptrack.egg-info/SOURCES.txt |
421 | -ptrack.egg-info/dependency_links.txt |
422 | -ptrack.egg-info/entry_points.txt |
423 | -ptrack.egg-info/requires.txt |
424 | -ptrack.egg-info/top_level.txt |
425 | diff --git a/ptrack.egg-info/dependency_links.txt b/ptrack.egg-info/dependency_links.txt |
426 | deleted file mode 100644 |
427 | index 8b13789..0000000 |
428 | --- a/ptrack.egg-info/dependency_links.txt |
429 | +++ /dev/null |
430 | @@ -1 +0,0 @@ |
431 | - |
432 | diff --git a/ptrack.egg-info/entry_points.txt b/ptrack.egg-info/entry_points.txt |
433 | deleted file mode 100644 |
434 | index 32a28e4..0000000 |
435 | --- a/ptrack.egg-info/entry_points.txt |
436 | +++ /dev/null |
437 | @@ -1,4 +0,0 @@ |
438 | -[console_scripts] |
439 | -ptc = ptrack.main:copy |
440 | -ptm = ptrack.main:move |
441 | -ptrack = ptrack.main:main |
442 | diff --git a/ptrack.egg-info/requires.txt b/ptrack.egg-info/requires.txt |
443 | deleted file mode 100644 |
444 | index 382c1b3..0000000 |
445 | --- a/ptrack.egg-info/requires.txt |
446 | +++ /dev/null |
447 | @@ -1,3 +0,0 @@ |
448 | -rich |
449 | -argparse |
450 | -argcomplete |
451 | diff --git a/ptrack.egg-info/top_level.txt b/ptrack.egg-info/top_level.txt |
452 | deleted file mode 100644 |
453 | index c003217..0000000 |
454 | --- a/ptrack.egg-info/top_level.txt |
455 | +++ /dev/null |
456 | @@ -1 +0,0 @@ |
457 | -ptrack |
458 | diff --git a/ptrack/__init__.py b/ptrack/__init__.py |
459 | index 57693c9..9b03a65 100644 |
460 | --- a/ptrack/__init__.py |
461 | +++ b/ptrack/__init__.py |
462 | @@ -1,11 +1,12 @@ |
463 | import argparse |
464 | import argcomplete |
465 | -version="0.1.4" |
466 | +version="0.2.1" |
467 | |
468 | parser = argparse.ArgumentParser(description='A simple CLI utility for asthetically tracking progress when copying or moving files.') |
469 | parser.add_argument('-v', '--verbose', action='store_true', help='verbose output') |
470 | parser.add_argument('-c', '--copy', action='store_true', help='copy files (You can use `ptc` instead of `ptrack -c`)') |
471 | parser.add_argument('-m', '--move', action='store_true', help='move files (You can use `ptm` instead of `ptrack -m`)') |
472 | +parser.add_argument('-d', '--download', action='store_true', help='download files (You can use `ptd` instead of `ptrack -d`)') |
473 | parser.add_argument('-V', '--version', action='version', version='%(prog)s' + version) |
474 | |
475 | argcomplete.autocomplete(parser) |
476 | @@ -14,3 +15,4 @@ args, unknown = parser.parse_known_args() |
477 | verbose = args.verbose |
478 | copy = args.copy |
479 | move = args.move |
480 | +download = args.download |
481 | diff --git a/ptrack/__pycache__/__init__.cpython-310.pyc b/ptrack/__pycache__/__init__.cpython-310.pyc |
482 | deleted file mode 100644 |
483 | index 08193c2..0000000 |
484 | Binary files a/ptrack/__pycache__/__init__.cpython-310.pyc and /dev/null differ |
485 | diff --git a/ptrack/__pycache__/main.cpython-310.pyc b/ptrack/__pycache__/main.cpython-310.pyc |
486 | deleted file mode 100644 |
487 | index 2c99988..0000000 |
488 | Binary files a/ptrack/__pycache__/main.cpython-310.pyc and /dev/null differ |
489 | diff --git a/ptrack/__pycache__/methods.cpython-310.pyc b/ptrack/__pycache__/methods.cpython-310.pyc |
490 | deleted file mode 100644 |
491 | index d4080cd..0000000 |
492 | Binary files a/ptrack/__pycache__/methods.cpython-310.pyc and /dev/null differ |
493 | diff --git a/ptrack/download.py b/ptrack/download.py |
494 | new file mode 100644 |
495 | index 0000000..35c5705 |
496 | --- /dev/null |
497 | +++ b/ptrack/download.py |
498 | @@ -0,0 +1,15 @@ |
499 | +import os |
500 | +import requests |
501 | +from rich.text import Text |
502 | +from rich.console import Console |
503 | +from rich.progress import Progress, TextColumn, BarColumn, TimeRemainingColumn, FileSizeColumn, Task, DownloadColumn, TimeElapsedColumn |
504 | +from ptrack.methods import CustomFileSizeColumn |
505 | +from datetime import timedelta |
506 | + |
507 | +import sys |
508 | +from humanize import naturalsize # Make sure to install this package using pip |
509 | + |
510 | + |
511 | + |
512 | + |
513 | + |
514 | diff --git a/ptrack/main.py b/ptrack/main.py |
515 | index cc43997..5730123 100644 |
516 | --- a/ptrack/main.py |
517 | +++ b/ptrack/main.py |
518 | @@ -1,14 +1,18 @@ |
519 | import os |
520 | import sys |
521 | import ptrack |
522 | -from ptrack.methods import format_file_size, regular_copy, verbose_copy, hlp, getTotalSize |
523 | +from ptrack.methods import format_file_size, regular_copy, verbose_copy, hlp, getTotalSize, CustomFileSizeColumn |
524 | from rich.progress import Progress, BarColumn, TextColumn, TimeRemainingColumn, FileSizeColumn |
525 | from rich.console import Console |
526 | +from datetime import timedelta |
527 | import shutil |
528 | +import requests |
529 | +import validators |
530 | |
531 | verbose = ptrack.verbose |
532 | argCopy = ptrack.copy |
533 | argMove = ptrack.move |
534 | +argDownload = ptrack.download |
535 | |
536 | |
537 | def run(process): |
538 | @@ -108,6 +112,68 @@ def run(process): |
539 | return srcPaths |
540 | |
541 | |
542 | +def download(): |
543 | + |
544 | + console = Console() |
545 | + urls = sys.argv[1:] |
546 | + |
547 | + if len(urls) == 0: |
548 | + console.print("\n[bold red][-][/bold red] No URL provided.\n") |
549 | + sys.exit() |
550 | + |
551 | + num_urls = len(urls) |
552 | + for url in urls: |
553 | + if url.startswith('-'): |
554 | + num_urls -= 1 |
555 | + elif not validators.url(url): |
556 | + console.print(f"\n[bold red][-][/bold red] Invalid URL: [bold yellow]{url}[/bold yellow]\n") |
557 | + sys.exit() |
558 | + |
559 | + console.print(f"\n[#ea2a6f]Downloading:[/#ea2a6f] [bold yellow]{num_urls}[/bold yellow] [bold cyan]files[/bold cyan]\n") |
560 | + |
561 | + errors = [] |
562 | + for url in urls: |
563 | + try: |
564 | + if url.startswith('-'): |
565 | + continue |
566 | + |
567 | + response = requests.get(url, stream=True) |
568 | + total_size_in_bytes = int(response.headers.get('content-length', 0)) |
569 | + destination_path = os.path.basename(url) |
570 | + |
571 | + with Progress( |
572 | + BarColumn(bar_width=50), |
573 | + "[progress.percentage]{task.percentage:>3.0f}%", |
574 | + TimeRemainingColumn(), |
575 | + "[#ea2a6f][[/#ea2a6f]", |
576 | + CustomFileSizeColumn(), |
577 | + "[#ea2a6f]][/#ea2a6f]", |
578 | + console=console, |
579 | + auto_refresh=True |
580 | + ) as progress: |
581 | + task_id = progress.add_task("Downloading", total=total_size_in_bytes) |
582 | + block_size = 1024 # 1 Kibibyte |
583 | + with open(destination_path, 'wb') as file: |
584 | + for data in response.iter_content(block_size): |
585 | + file.write(data) |
586 | + progress.update(task_id, advance=block_size) |
587 | + except KeyboardInterrupt: |
588 | + console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n") |
589 | + sys.exit(1) |
590 | + |
591 | + except Exception as e: |
592 | + console.print(f"\n[bold red]\[-][/bold red][bold white] Could not download file: [bold yellow]{url}[/bold yellow]\n") |
593 | + print(e) |
594 | + errors.append(url) |
595 | + |
596 | + if len(errors) == 0: |
597 | + console.print("\n[bold green]Download completed![/bold green]\n") |
598 | + else: |
599 | + console.print("[bold red]The following files could not be downloaded:[/bold red]\n") |
600 | + for error in errors: |
601 | + console.print(f"[bold red] -[/bold red][bold yellow]{error}[/bold yellow]\n") |
602 | + |
603 | + |
604 | def copy(): |
605 | run('Copying') |
606 | |
607 | @@ -126,6 +192,8 @@ def main(): |
608 | move() |
609 | elif argCopy: |
610 | copy() |
611 | + elif argDownload: |
612 | + download() |
613 | else: |
614 | hlp() |
615 | |
616 | diff --git a/ptrack/methods.py b/ptrack/methods.py |
617 | index cbe9420..1c7482c 100644 |
618 | --- a/ptrack/methods.py |
619 | +++ b/ptrack/methods.py |
620 | @@ -1,5 +1,13 @@ |
621 | import os |
622 | -from rich.progress import Progress, BarColumn, TextColumn, TimeRemainingColumn, FileSizeColumn |
623 | +import sys |
624 | +import requests |
625 | +from rich.console import Console |
626 | +from rich.progress import Progress, TextColumn, BarColumn, TimeRemainingColumn, FileSizeColumn, Task, DownloadColumn, TimeElapsedColumn |
627 | +from rich.text import Text |
628 | +from datetime import timedelta |
629 | +from humanize import naturalsize # Make sure to install this package using pip |
630 | + |
631 | +console = Console() |
632 | |
633 | |
634 | def getTotalSize(srcPaths): |
635 | @@ -82,13 +90,47 @@ def verbose_copy(src, dst, console, current, total_files): |
636 | |
637 | def hlp(): |
638 | print(""" |
639 | -usage: ptrack [-h] [-v] [-c] [-m] |
640 | +usage: ptrack [-h] [-v] [-c] [-m] [-d] [-V] |
641 | |
642 | A simple CLI utility for asthetically tracking progress when copying or moving files. |
643 | |
644 | options: |
645 | - -h, --help show this help message and exit |
646 | - -v, --verbose verbose output |
647 | - -c, --copy copy files (You can use `ptc` instead of `ptrack -c`) |
648 | - -m, --move move files (You can use `ptm` instead of `ptrack -m`) |
649 | + -h, --help show this help message and exit |
650 | + -v, --verbose verbose output |
651 | + -c, --copy copy files (You can use `ptc` instead of `ptrack -c`) |
652 | + -m, --move move files (You can use `ptm` instead of `ptrack -m`) |
653 | + -d, --download download files (You can use `ptd` instead of `ptrack -d`) |
654 | + -V, --version show program's version number and exit |
655 | """) |
656 | + |
657 | + |
658 | +class CustomFileSizeColumn(FileSizeColumn, TimeElapsedColumn): |
659 | + def render(self, task): |
660 | + completed = task.completed |
661 | + total = task.total |
662 | + elapsed = task.elapsed |
663 | + |
664 | + if elapsed > 0.0: # Prevent division by zero |
665 | + download_speed = completed / elapsed # calculate download rate |
666 | + else: |
667 | + download_speed = 0 |
668 | + |
669 | + if total: |
670 | + size = Text.assemble( |
671 | + (f"{self._human_readable_size(completed)}", "green"), # completed |
672 | + (" / ", "none"), # separator |
673 | + (f"{self._human_readable_size(total)}", "red"), # total |
674 | + (" [", "none"), # opening square bracket |
675 | + (f"{self._human_readable_size(download_speed)}/s", "blue"), # download rate |
676 | + ("]", "none"), # closing square bracket |
677 | + ) |
678 | + else: |
679 | + size = Text(str(self._human_readable_size(completed))) |
680 | + return size |
681 | + |
682 | + def _human_readable_size(self, size: int) -> str: |
683 | + for unit in ['B', 'KB', 'MB', 'GB', 'TB']: |
684 | + if abs(size) < 1024.0: |
685 | + return f"{size:.1f}{unit}" |
686 | + size /= 1024.0 |
687 | + return f"{size:.1f}PB" |
688 | diff --git a/setup.py b/setup.py |
689 | index 9447900..a769eb4 100644 |
690 | --- a/setup.py |
691 | +++ b/setup.py |
692 | @@ -2,20 +2,22 @@ from setuptools import setup, find_packages |
693 | |
694 | setup( |
695 | name='ptrack', |
696 | - version="0.1.4", |
697 | - description='A simple CLI utility for asthetically tracking progress when copying or moving files.', |
698 | + version="0.2.1", |
699 | + description='A simple CLI utility for asthetically tracking progress when copying, moving or downloading files.', |
700 | author='Connor Etherington', |
701 | author_email='[email protected]', |
702 | packages=find_packages(), |
703 | install_requires=[ |
704 | 'rich', |
705 | 'argparse', |
706 | - 'argcomplete', |
707 | + 'requests', |
708 | + 'validators', |
709 | ], |
710 | entry_points={ |
711 | 'console_scripts': [ |
712 | 'ptc=ptrack.main:copy', |
713 | 'ptm=ptrack.main:move', |
714 | + 'ptd=ptrack.main:download', |
715 | 'ptrack=ptrack.main:main', |
716 | ] |
717 | } |