ptrack


Logs | Files | README | README | LICENSE | LICENSE | GitLab


1
commit d2fe27f72c91445605eaef0d5a4f445c9904935c
2
Author: Connor Etherington <[email protected]>
3
Date:   Tue Aug 22 14:34:20 2023 +0200
4
5
    Auto-Commit Update - 20230822
6
---
7
 PKGBUILD                             |   2 +-
8
 README.md                            |   2 +-
9
 build/lib/ptrack/__init__.py         |  16 +++
10
 build/lib/ptrack/main.py             | 207 +++++++++++++++++++++++++++++++++++
11
 build/lib/ptrack/methods.py          | 136 +++++++++++++++++++++++
12
 dist/ptrack-0.2.2-py3-none-any.whl   | Bin 0 -> 6551 bytes
13
 dist/ptrack-0.2.2.tar.gz             | Bin 0 -> 6568 bytes
14
 ptrack.egg-info/PKG-INFO             |   7 ++
15
 ptrack.egg-info/SOURCES.txt          |  12 ++
16
 ptrack.egg-info/dependency_links.txt |   1 +
17
 ptrack.egg-info/entry_points.txt     |   5 +
18
 ptrack.egg-info/requires.txt         |   6 +
19
 ptrack.egg-info/top_level.txt        |   1 +
20
 ptrack/__init__.py                   |   4 +-
21
 ptrack/main.py                       |  21 ++--
22
 ptrack/methods.py                    |   8 +-
23
 recipe/meta.yaml                     |   2 +-
24
 setup.py                             |   4 +-
25
 18 files changed, 415 insertions(+), 19 deletions(-)
26
27
diff --git a/PKGBUILD b/PKGBUILD
28
index 9cbf2c1..024da0a 100644
29
--- a/PKGBUILD
30
+++ b/PKGBUILD
31
@@ -1,7 +1,7 @@
32
 # Maintainer: Connor Etherington <[email protected]>
33
 # ---
34
 pkgname=ptrack
35
-pkgver=0.2.1
36
+pkgver=0.2.2
37
 pkgrel=1
38
 pkgdesc="A simple CLI utility for asthetically tracking progress when copying, moving or downloading files."
39
 arch=(x86_64)
40
diff --git a/README.md b/README.md
41
index e2cc0aa..f1130dd 100644
42
--- a/README.md
43
+++ b/README.md
44
@@ -3,7 +3,7 @@
45
 ### Welcome to ptrack, a powerful and user-friendly CLI utility for tracking the progress of your file operations.
46
 ### 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.
47
 
48
-*Version: 0.2.1*
49
+*Version: 0.2.2*
50
 
51
 ***
52
 
53
diff --git a/build/lib/ptrack/__init__.py b/build/lib/ptrack/__init__.py
54
new file mode 100644
55
index 0000000..112f15e
56
--- /dev/null
57
+++ b/build/lib/ptrack/__init__.py
58
@@ -0,0 +1,16 @@
59
+import argparse
60
+version="0.2.2"
61
+
62
+parser = argparse.ArgumentParser(description='A simple CLI utility for asthetically tracking progress when copying or moving files.')
63
+parser.add_argument('-v', '--verbose', action='store_true', help='verbose output')
64
+parser.add_argument('-c', '--copy', action='store_true', help='copy files (You can use `ptc` instead of `ptrack -c`)')
65
+parser.add_argument('-m', '--move', action='store_true', help='move files (You can use `ptm` instead of `ptrack -m`)')
66
+parser.add_argument('-d', '--download', action='store_true', help='download files (You can use `ptd` instead of `ptrack -d`)')
67
+parser.add_argument('-V', '--version', action='version', version='%(prog)s' + version)
68
+
69
+args, unknown = parser.parse_known_args()
70
+
71
+verbose = args.verbose
72
+copy = args.copy
73
+move = args.move
74
+download = args.download
75
diff --git a/build/lib/ptrack/main.py b/build/lib/ptrack/main.py
76
new file mode 100644
77
index 0000000..48523fa
78
--- /dev/null
79
+++ b/build/lib/ptrack/main.py
80
@@ -0,0 +1,207 @@
81
+import os
82
+import re
83
+import sys
84
+import ptrack
85
+from ptrack.methods import format_file_size, regular_copy, verbose_copy, hlp, getTotalSize, CustomFileSizeColumn
86
+from rich.progress import Progress, BarColumn, TextColumn, TimeRemainingColumn, FileSizeColumn
87
+from rich.console import Console
88
+from datetime import timedelta
89
+import shutil
90
+import requests
91
+import validators
92
+
93
+verbose = ptrack.verbose
94
+argCopy = ptrack.copy
95
+argMove = ptrack.move
96
+argDownload = ptrack.download
97
+
98
+
99
+def run(process):
100
+    console = Console()
101
+
102
+    if len(sys.argv) < 3:
103
+        hlp()
104
+        if process == "Copying":
105
+            console.print("[bold cyan]Usage: ptc [OPTIONS] SOURCE... DESTINATION[/bold cyan]")
106
+        elif process == "Moving":
107
+            console.print("[bold cyan]Usage: ptm [OPTIONS] SOURCE... DESTINATION[/bold cyan]")
108
+        sys.exit(1)
109
+
110
+    src_paths = sys.argv[1:-1]
111
+    dst = sys.argv[-1]
112
+    srcPaths = []
113
+
114
+    for path in src_paths:
115
+        if path.endswith('/'):
116
+            path = path[:-1]
117
+        srcPaths.append(path)
118
+
119
+    if os.path.isdir(dst):
120
+        dst_dir = dst
121
+        new_name = None
122
+    else:
123
+        dst_dir = os.path.dirname(dst)
124
+        new_name = os.path.basename(dst)
125
+
126
+    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))
127
+    total_size = getTotalSize(srcPaths)
128
+
129
+    current_file = 1
130
+
131
+    if total_files > 1:
132
+        console.print(f"\n[#ea2a6f]{process}:[/#ea2a6f] [bold cyan]{total_files} files[/bold cyan]\n")
133
+    else:
134
+        for src_path in srcPaths:
135
+            if os.path.isfile(src_path):
136
+                console.print(f"\n[#ea2a6f]{process}:[/#ea2a6f] [bold cyan] {os.path.basename(src_path)} [/bold cyan]\n")
137
+
138
+    if verbose:
139
+        for src_path in srcPaths:
140
+            if os.path.isfile(src_path):
141
+                dst_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name)
142
+                terminate = verbose_copy(src_path, dst_path, console, current_file, total_files, file_name=os.path.basename(src_path))
143
+                current_file += 1
144
+                if terminate == 'c':
145
+                    console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
146
+                    sys.exit(1)
147
+            else:
148
+                for root, dirs, files in os.walk(src_path):
149
+                    for file in files:
150
+                        src_file_path = os.path.join(root, file)
151
+                        relative_path = os.path.relpath(src_file_path, start=src_path)
152
+                        dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name, relative_path)
153
+                        os.makedirs(os.path.dirname(src_file_path), exist_ok=True)
154
+                        terminate = verbose_copy(src_file_path, dst_file_path, console, current_file, total_files, file_name=file)
155
+                        current_file += 1
156
+                        if terminate == 'c':
157
+                            console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
158
+                            sys.exit(1)
159
+    else:
160
+        with Progress(
161
+            BarColumn(bar_width=50),
162
+            "[progress.percentage]{task.percentage:>3.0f}%",
163
+            TimeRemainingColumn(),
164
+            "[#ea2a6f][[/#ea2a6f]",
165
+            FileSizeColumn(),
166
+            "[#ea2a6f]/[/#ea2a6f]",
167
+            TextColumn("[bold cyan]{task.fields[total_size]}[/bold cyan]"),
168
+            "[#ea2a6f]][/#ea2a6f]",
169
+            console=console,
170
+            auto_refresh=False
171
+        ) as progress:
172
+            task = progress.add_task("", total=total_size, total_size=format_file_size(total_size))
173
+
174
+            for src_path in srcPaths:
175
+                if os.path.isfile(src_path):
176
+                    dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name)
177
+                    terminate = regular_copy(src_path, dst_file_path, console, task, progress, file_name=os.path.basename(src_path))
178
+                    if terminate == 'c':
179
+                        console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
180
+                        sys.exit(1)
181
+                else:
182
+                    for root, dirs, files in os.walk(src_path):
183
+                        for file in files:
184
+                            src_file_path = os.path.join(root, file)
185
+                            relative_path = os.path.relpath(src_file_path, start=src_path)
186
+                            dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name, relative_path)
187
+                            os.makedirs(os.path.dirname(dst_file_path), exist_ok=True)
188
+                            terminate = regular_copy(src_file_path, dst_file_path, console, task, progress, file_name=file)
189
+                            if terminate == 'c':
190
+                                console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
191
+                                sys.exit(1)
192
+
193
+    return srcPaths
194
+
195
+
196
+def download():
197
+    console = Console()
198
+    urls = sys.argv[1:]
199
+
200
+    if len(urls) == 0:
201
+        console.print("\n[bold red][-][/bold red] No URL provided.\n")
202
+        sys.exit()
203
+
204
+    num_urls = len(urls)
205
+    for url in urls:
206
+        if url.startswith('-'):
207
+            num_urls -= 1
208
+        elif not validators.url(url):
209
+            console.print(f"\n[bold red][-][/bold red] Invalid URL: [bold yellow]{url}[/bold yellow]\n")
210
+            sys.exit()
211
+
212
+    console.print(f"\n[#ea2a6f]Downloading:[/#ea2a6f] [bold yellow]{num_urls}[/bold yellow] [bold cyan]files[/bold cyan]\n")
213
+
214
+    errors = []
215
+    for url in urls:
216
+        try:
217
+            if url.startswith('-'):
218
+                continue
219
+
220
+            response = requests.get(url, stream=True, allow_redirects=True)
221
+            total_size_in_bytes = int(response.headers.get('content-length', 0))
222
+            content_disposition = response.headers.get('content-disposition')
223
+            if content_disposition:
224
+                destination_path = re.findall('filename="(.+)"', content_disposition)[0]
225
+            else:
226
+                destination_path = os.path.basename(url)
227
+
228
+            with Progress(
229
+                BarColumn(bar_width=50),
230
+                "[progress.percentage]{task.percentage:>3.0f}%",
231
+                TimeRemainingColumn(),
232
+                "[#ea2a6f][[/#ea2a6f]",
233
+                CustomFileSizeColumn(),
234
+                "[#ea2a6f]][/#ea2a6f]",
235
+                f" {destination_path}",  # This line will print the filename at the end
236
+                console=console,
237
+                auto_refresh=True
238
+            ) as progress:
239
+                task_id = progress.add_task("Downloading", total=total_size_in_bytes)
240
+                block_size = 1024  # 1 Kibibyte
241
+                with open(destination_path, 'wb') as file:
242
+                    for data in response.iter_content(block_size):
243
+                        file.write(data)
244
+                        progress.update(task_id, advance=block_size)
245
+        except KeyboardInterrupt:
246
+            console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
247
+            sys.exit(1)
248
+
249
+        except Exception as e:
250
+            console.print(f"\n[bold red]\[-][/bold red][bold white] Could not download file: [bold yellow]{url}[/bold yellow]\n")
251
+            print(e)
252
+            errors.append(url)
253
+
254
+    if len(errors) == 0:
255
+        console.print("\n[bold green]Download completed![/bold green]\n")
256
+    else:
257
+        console.print("[bold red]The following files could not be downloaded:[/bold red]\n")
258
+        for error in errors:
259
+            console.print(f"[bold red]   -[/bold red][bold yellow]{error}[/bold yellow]\n")
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
+    elif argDownload:
281
+        download()
282
+    else:
283
+        hlp()
284
+
285
+
286
+if __name__ == "__main__":
287
+    main()
288
diff --git a/build/lib/ptrack/methods.py b/build/lib/ptrack/methods.py
289
new file mode 100644
290
index 0000000..d79173d
291
--- /dev/null
292
+++ b/build/lib/ptrack/methods.py
293
@@ -0,0 +1,136 @@
294
+import os
295
+import sys
296
+import requests
297
+from rich.console import Console
298
+from rich.progress import Progress, TextColumn, BarColumn, TimeRemainingColumn, FileSizeColumn, Task, DownloadColumn, TimeElapsedColumn
299
+from rich.text import Text
300
+from datetime import timedelta
301
+from humanize import naturalsize
302
+
303
+console = Console()
304
+
305
+
306
+def getTotalSize(srcPaths):
307
+    total_size = 0
308
+    for path in srcPaths:
309
+        if os.path.isfile(path):
310
+            total_size += os.path.getsize(path)
311
+        else:
312
+            for r, d, files in os.walk(path):
313
+                for f in files:
314
+                    fp = os.path.join(r, f)
315
+                    total_size += os.path.getsize(fp)
316
+    return total_size
317
+
318
+
319
+def format_file_size(file_size):
320
+    if file_size >= 1000 ** 4:  # Terabyte
321
+        return f"{round(file_size / (1000 ** 4))} TB"
322
+    elif file_size >= 1000 ** 3:  # Gigabyte
323
+        return f"{round(file_size / (1000 ** 3))} GB"
324
+    elif file_size >= 1000 ** 2:  # Megabyte
325
+        return f"{round(file_size / (1000 ** 2))} MB"
326
+    elif file_size >= 1000:  # Kilobyte
327
+        return f"{round(file_size / 1000)} kB"
328
+    else:  # Byte
329
+        return f"{file_size} bytes"
330
+
331
+
332
+def regular_copy(src, dst, console, task, progress, file_name):
333
+    operation_cancelled = False
334
+    try:
335
+        with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
336
+            while True:
337
+                buf = fsrc.read(1024*1024)
338
+                if not buf or operation_cancelled:
339
+                    break
340
+                fdst.write(buf)
341
+                progress.update(task, advance=len(buf))
342
+                progress.refresh()
343
+
344
+    except KeyboardInterrupt:
345
+        operation_cancelled = True
346
+        progress.stop()
347
+        return "c"
348
+
349
+
350
+def verbose_copy(src, dst, console, current, total_files, file_name):
351
+    operation_cancelled = False
352
+    file_size = os.path.getsize(src)
353
+
354
+    with Progress(
355
+        BarColumn(bar_width=50),
356
+        "[progress.percentage]{task.percentage:>3.0f}%",
357
+        TimeRemainingColumn(),
358
+        "[#ea2a6f][[/#ea2a6f]",
359
+        FileSizeColumn(),
360
+        "[#ea2a6f]/[/#ea2a6f]",
361
+        TextColumn(f"[bold cyan]{format_file_size(file_size)}[/bold cyan]"),
362
+        "[#ea2a6f]][/#ea2a6f]",
363
+        f"({current} of {total_files}) - {file_name}",
364
+        console=console,
365
+        auto_refresh=False
366
+    ) as progress:
367
+        task = progress.add_task("", total=file_size, file_size=format_file_size(file_size))
368
+
369
+        try:
370
+            with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
371
+                while not progress.finished:
372
+                    buf = fsrc.read(1024*1024)
373
+                    if not buf or operation_cancelled:
374
+                        break
375
+                    fdst.write(buf)
376
+                    progress.update(task, advance=len(buf))
377
+                    progress.refresh()
378
+        except KeyboardInterrupt:
379
+            operation_cancelled = True
380
+            progress.stop()
381
+            return "c"
382
+
383
+
384
+def hlp():
385
+    print("""
386
+usage: ptrack [-h] [-v] [-c] [-m] [-d] [-V]
387
+
388
+A simple CLI utility for asthetically tracking progress when copying or moving files.
389
+
390
+options:
391
+  -h, --help      show this help message and exit
392
+  -v, --verbose   verbose output
393
+  -c, --copy      copy files (You can use `ptc` instead of `ptrack -c`)
394
+  -m, --move      move files (You can use `ptm` instead of `ptrack -m`)
395
+  -d, --download  download files (You can use `ptd` instead of `ptrack -d`)
396
+  -V, --version   show program's version number and exit
397
+""")
398
+
399
+
400
+class CustomFileSizeColumn(FileSizeColumn, TimeElapsedColumn):
401
+    def render(self, task):
402
+        completed = task.completed
403
+        total = task.total
404
+        elapsed = task.elapsed
405
+
406
+        if elapsed > 0.0:  # Prevent division by zero
407
+            download_speed = completed / elapsed  # calculate download rate
408
+        else:
409
+            download_speed = 0
410
+
411
+        if total:
412
+            size = Text.assemble(
413
+                (f"{self._human_readable_size(completed)}", "green"),  # completed
414
+                (" / ", "none"),  # separator
415
+                (f"{self._human_readable_size(total)}", "red"),  # total
416
+                (" [", "none"),  # opening square bracket
417
+                (f"{self._human_readable_size(download_speed)}/s", "blue"),  # download rate
418
+                ("]", "none"),  # closing square bracket
419
+            )
420
+        else:
421
+            size = Text(str(self._human_readable_size(completed)))
422
+        return size
423
+
424
+    def _human_readable_size(self, size: int) -> str:
425
+        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
426
+            if abs(size) < 1024.0:
427
+                return f"{size:.1f}{unit}"
428
+            size /= 1024.0
429
+        return f"{size:.1f}PB"
430
diff --git a/dist/ptrack-0.2.2-py3-none-any.whl b/dist/ptrack-0.2.2-py3-none-any.whl
431
new file mode 100644
432
index 0000000..b1836bd
433
Binary files /dev/null and b/dist/ptrack-0.2.2-py3-none-any.whl differ
434
diff --git a/dist/ptrack-0.2.2.tar.gz b/dist/ptrack-0.2.2.tar.gz
435
new file mode 100644
436
index 0000000..ac589df
437
Binary files /dev/null and b/dist/ptrack-0.2.2.tar.gz differ
438
diff --git a/ptrack.egg-info/PKG-INFO b/ptrack.egg-info/PKG-INFO
439
new file mode 100644
440
index 0000000..2ce3426
441
--- /dev/null
442
+++ b/ptrack.egg-info/PKG-INFO
443
@@ -0,0 +1,7 @@
444
+Metadata-Version: 2.1
445
+Name: ptrack
446
+Version: 0.2.2
447
+Summary: A simple CLI utility for asthetically tracking progress when copying, moving or downloading files.
448
+Author: Connor Etherington
449
+Author-email: [email protected]
450
+License-File: LICENSE
451
diff --git a/ptrack.egg-info/SOURCES.txt b/ptrack.egg-info/SOURCES.txt
452
new file mode 100644
453
index 0000000..086a784
454
--- /dev/null
455
+++ b/ptrack.egg-info/SOURCES.txt
456
@@ -0,0 +1,12 @@
457
+LICENSE
458
+README.md
459
+setup.py
460
+ptrack/__init__.py
461
+ptrack/main.py
462
+ptrack/methods.py
463
+ptrack.egg-info/PKG-INFO
464
+ptrack.egg-info/SOURCES.txt
465
+ptrack.egg-info/dependency_links.txt
466
+ptrack.egg-info/entry_points.txt
467
+ptrack.egg-info/requires.txt
468
+ptrack.egg-info/top_level.txt
469
diff --git a/ptrack.egg-info/dependency_links.txt b/ptrack.egg-info/dependency_links.txt
470
new file mode 100644
471
index 0000000..8b13789
472
--- /dev/null
473
+++ b/ptrack.egg-info/dependency_links.txt
474
@@ -0,0 +1 @@
475
+
476
diff --git a/ptrack.egg-info/entry_points.txt b/ptrack.egg-info/entry_points.txt
477
new file mode 100644
478
index 0000000..ea851b3
479
--- /dev/null
480
+++ b/ptrack.egg-info/entry_points.txt
481
@@ -0,0 +1,5 @@
482
+[console_scripts]
483
+ptc = ptrack.main:copy
484
+ptd = ptrack.main:download
485
+ptm = ptrack.main:move
486
+ptrack = ptrack.main:main
487
diff --git a/ptrack.egg-info/requires.txt b/ptrack.egg-info/requires.txt
488
new file mode 100644
489
index 0000000..d19a378
490
--- /dev/null
491
+++ b/ptrack.egg-info/requires.txt
492
@@ -0,0 +1,6 @@
493
+rich
494
+argparse
495
+requests
496
+validators
497
+setuptools
498
+humanize
499
diff --git a/ptrack.egg-info/top_level.txt b/ptrack.egg-info/top_level.txt
500
new file mode 100644
501
index 0000000..c003217
502
--- /dev/null
503
+++ b/ptrack.egg-info/top_level.txt
504
@@ -0,0 +1 @@
505
+ptrack
506
diff --git a/ptrack/__init__.py b/ptrack/__init__.py
507
index 9b03a65..112f15e 100644
508
--- a/ptrack/__init__.py
509
+++ b/ptrack/__init__.py
510
@@ -1,6 +1,5 @@
511
 import argparse
512
-import argcomplete
513
-version="0.2.1"
514
+version="0.2.2"
515
 
516
 parser = argparse.ArgumentParser(description='A simple CLI utility for asthetically tracking progress when copying or moving files.')
517
 parser.add_argument('-v', '--verbose', action='store_true', help='verbose output')
518
@@ -9,7 +8,6 @@ parser.add_argument('-m', '--move', action='store_true', help='move files (You c
519
 parser.add_argument('-d', '--download', action='store_true', help='download files (You can use `ptd` instead of `ptrack -d`)')
520
 parser.add_argument('-V', '--version', action='version', version='%(prog)s' + version)
521
 
522
-argcomplete.autocomplete(parser)
523
 args, unknown = parser.parse_known_args()
524
 
525
 verbose = args.verbose
526
diff --git a/ptrack/main.py b/ptrack/main.py
527
index 5730123..48523fa 100644
528
--- a/ptrack/main.py
529
+++ b/ptrack/main.py
530
@@ -1,4 +1,5 @@
531
 import os
532
+import re
533
 import sys
534
 import ptrack
535
 from ptrack.methods import format_file_size, regular_copy, verbose_copy, hlp, getTotalSize, CustomFileSizeColumn
536
@@ -58,7 +59,7 @@ def run(process):
537
         for src_path in srcPaths:
538
             if os.path.isfile(src_path):
539
                 dst_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name)
540
-                terminate = verbose_copy(src_path, dst_path, console, current_file, total_files)
541
+                terminate = verbose_copy(src_path, dst_path, console, current_file, total_files, file_name=os.path.basename(src_path))
542
                 current_file += 1
543
                 if terminate == 'c':
544
                     console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
545
@@ -69,8 +70,8 @@ def run(process):
546
                         src_file_path = os.path.join(root, file)
547
                         relative_path = os.path.relpath(src_file_path, start=src_path)
548
                         dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name, relative_path)
549
-                        os.makedirs(os.path.dirname(dst_file_path), exist_ok=True)
550
-                        terminate = verbose_copy(src_file_path, dst_file_path, console, current_file, total_files)
551
+                        os.makedirs(os.path.dirname(src_file_path), exist_ok=True)
552
+                        terminate = verbose_copy(src_file_path, dst_file_path, console, current_file, total_files, file_name=file)
553
                         current_file += 1
554
                         if terminate == 'c':
555
                             console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
556
@@ -93,7 +94,7 @@ def run(process):
557
             for src_path in srcPaths:
558
                 if os.path.isfile(src_path):
559
                     dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name)
560
-                    terminate = regular_copy(src_path, dst_file_path, console, task, progress)
561
+                    terminate = regular_copy(src_path, dst_file_path, console, task, progress, file_name=os.path.basename(src_path))
562
                     if terminate == 'c':
563
                         console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
564
                         sys.exit(1)
565
@@ -104,7 +105,7 @@ def run(process):
566
                             relative_path = os.path.relpath(src_file_path, start=src_path)
567
                             dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name, relative_path)
568
                             os.makedirs(os.path.dirname(dst_file_path), exist_ok=True)
569
-                            terminate = regular_copy(src_file_path, dst_file_path, console, task, progress)
570
+                            terminate = regular_copy(src_file_path, dst_file_path, console, task, progress, file_name=file)
571
                             if terminate == 'c':
572
                                 console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
573
                                 sys.exit(1)
574
@@ -113,7 +114,6 @@ def run(process):
575
 
576
 
577
 def download():
578
-
579
     console = Console()
580
     urls = sys.argv[1:]
581
 
582
@@ -137,9 +137,13 @@ def download():
583
             if url.startswith('-'):
584
                 continue
585
 
586
-            response = requests.get(url, stream=True)
587
+            response = requests.get(url, stream=True, allow_redirects=True)
588
             total_size_in_bytes = int(response.headers.get('content-length', 0))
589
-            destination_path = os.path.basename(url)
590
+            content_disposition = response.headers.get('content-disposition')
591
+            if content_disposition:
592
+                destination_path = re.findall('filename="(.+)"', content_disposition)[0]
593
+            else:
594
+                destination_path = os.path.basename(url)
595
 
596
             with Progress(
597
                 BarColumn(bar_width=50),
598
@@ -148,6 +152,7 @@ def download():
599
                 "[#ea2a6f][[/#ea2a6f]",
600
                 CustomFileSizeColumn(),
601
                 "[#ea2a6f]][/#ea2a6f]",
602
+                f" {destination_path}",  # This line will print the filename at the end
603
                 console=console,
604
                 auto_refresh=True
605
             ) as progress:
606
diff --git a/ptrack/methods.py b/ptrack/methods.py
607
index 1c7482c..d79173d 100644
608
--- a/ptrack/methods.py
609
+++ b/ptrack/methods.py
610
@@ -5,7 +5,7 @@ from rich.console import Console
611
 from rich.progress import Progress, TextColumn, BarColumn, TimeRemainingColumn, FileSizeColumn, Task, DownloadColumn, TimeElapsedColumn
612
 from rich.text import Text
613
 from datetime import timedelta
614
-from humanize import naturalsize  # Make sure to install this package using pip
615
+from humanize import naturalsize
616
 
617
 console = Console()
618
 
619
@@ -36,7 +36,7 @@ def format_file_size(file_size):
620
         return f"{file_size} bytes"
621
 
622
 
623
-def regular_copy(src, dst, console, task, progress):
624
+def regular_copy(src, dst, console, task, progress, file_name):
625
     operation_cancelled = False
626
     try:
627
         with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
628
@@ -54,7 +54,7 @@ def regular_copy(src, dst, console, task, progress):
629
         return "c"
630
 
631
 
632
-def verbose_copy(src, dst, console, current, total_files):
633
+def verbose_copy(src, dst, console, current, total_files, file_name):
634
     operation_cancelled = False
635
     file_size = os.path.getsize(src)
636
 
637
@@ -67,7 +67,7 @@ def verbose_copy(src, dst, console, current, total_files):
638
         "[#ea2a6f]/[/#ea2a6f]",
639
         TextColumn(f"[bold cyan]{format_file_size(file_size)}[/bold cyan]"),
640
         "[#ea2a6f]][/#ea2a6f]",
641
-        f"({current} of {total_files})",
642
+        f"({current} of {total_files}) - {file_name}",
643
         console=console,
644
         auto_refresh=False
645
     ) as progress:
646
diff --git a/recipe/meta.yaml b/recipe/meta.yaml
647
index 571dcf1..3747a0a 100644
648
--- a/recipe/meta.yaml
649
+++ b/recipe/meta.yaml
650
@@ -1,6 +1,6 @@
651
 package:
652
   name: ptrack
653
-  version: 0.2.1
654
+  version: 0.2.2
655
 
656
 source:
657
   path: ..
658
diff --git a/setup.py b/setup.py
659
index a769eb4..4728915 100644
660
--- a/setup.py
661
+++ b/setup.py
662
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
663
 
664
 setup(
665
     name='ptrack',
666
-    version="0.2.1",
667
+    version="0.2.2",
668
     description='A simple CLI utility for asthetically tracking progress when copying, moving or downloading files.',
669
     author='Connor Etherington',
670
     author_email='[email protected]',
671
@@ -12,6 +12,8 @@ setup(
672
         'argparse',
673
         'requests',
674
         'validators',
675
+        'setuptools',
676
+        'humanize',
677
     ],
678
     entry_points={
679
         'console_scripts': [