ptrack


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


1
commit 83a9c043b8880d0b75b4f4068c72e15d0dbc2d49
2
Author: Connor Etherington <[email protected]>
3
Date:   Sat Sep 9 23:26:11 2023 +0200
4
5
    Auto-Commit Update - 20230909
6
---
7
 PKGBUILD                             |   2 +-
8
 README.md                            |   2 +-
9
 build/lib/ptrack/__init__.py         |  16 ---
10
 build/lib/ptrack/main.py             | 204 -----------------------------------
11
 build/lib/ptrack/methods.py          | 136 -----------------------
12
 dist/ptrack-0.2.4-py3-none-any.whl   | Bin 6550 -> 0 bytes
13
 dist/ptrack-0.2.4.tar.gz             | Bin 6709 -> 0 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                   |   2 +-
21
 ptrack/main.py                       |  46 ++++----
22
 ptrack/methods.py                    |   8 +-
23
 recipe/meta.yaml                     |   2 +-
24
 setup.py                             |   2 +-
25
 18 files changed, 37 insertions(+), 415 deletions(-)
26
27
diff --git a/PKGBUILD b/PKGBUILD
28
index 51862bc..e051730 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.4
36
+pkgver=0.2.5
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 019d811..7943082 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.4*
49
+*Version: 0.2.5*
50
 
51
 ***
52
 
53
diff --git a/build/lib/ptrack/__init__.py b/build/lib/ptrack/__init__.py
54
deleted file mode 100644
55
index 0e7f0c7..0000000
56
--- a/build/lib/ptrack/__init__.py
57
+++ /dev/null
58
@@ -1,16 +0,0 @@
59
-import argparse
60
-version="0.2.4"
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
deleted file mode 100644
77
index 48419be..0000000
78
--- a/build/lib/ptrack/main.py
79
+++ /dev/null
80
@@ -1,204 +0,0 @@
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
-            destination_path = re.findall('filename="(.+)"', content_disposition)[0] if content_disposition and re.findall('filename="(.+)"', content_disposition) else os.path.basename(url)
224
-
225
-            with Progress(
226
-                BarColumn(bar_width=50),
227
-                "[progress.percentage]{task.percentage:>3.0f}%",
228
-                TimeRemainingColumn(),
229
-                "[#ea2a6f][[/#ea2a6f]",
230
-                CustomFileSizeColumn(),
231
-                "[#ea2a6f]][/#ea2a6f]",
232
-                f" {destination_path}",  # This line will print the filename at the end
233
-                console=console,
234
-                auto_refresh=True
235
-            ) as progress:
236
-                task_id = progress.add_task("Downloading", total=total_size_in_bytes)
237
-                block_size = 1024  # 1 Kibibyte
238
-                with open(destination_path, 'wb') as file:
239
-                    for data in response.iter_content(block_size):
240
-                        file.write(data)
241
-                        progress.update(task_id, advance=block_size)
242
-        except KeyboardInterrupt:
243
-            console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
244
-            sys.exit(1)
245
-
246
-        except Exception as e:
247
-            console.print(f"\n[bold red]\[-][/bold red][bold white] Could not download file: [bold yellow]{url}[/bold yellow]\n")
248
-            print(e)
249
-            errors.append(url)
250
-
251
-    if len(errors) == 0:
252
-        console.print("\n[bold green]Download completed![/bold green]\n")
253
-    else:
254
-        console.print("[bold red]The following files could not be downloaded:[/bold red]\n")
255
-        for error in errors:
256
-            console.print(f"[bold red]   -[/bold red][bold yellow]{error}[/bold yellow]\n")
257
-
258
-
259
-def copy():
260
-    run('Copying')
261
-
262
-
263
-def move():
264
-    src_paths = run('Moving')
265
-    for src_path in src_paths:
266
-        if os.path.isfile(src_path):
267
-            os.remove(src_path)
268
-        else:
269
-            shutil.rmtree(src_path)
270
-
271
-
272
-def main():
273
-    if argMove:
274
-        move()
275
-    elif argCopy:
276
-        copy()
277
-    elif argDownload:
278
-        download()
279
-    else:
280
-        hlp()
281
-
282
-
283
-if __name__ == "__main__":
284
-    main()
285
diff --git a/build/lib/ptrack/methods.py b/build/lib/ptrack/methods.py
286
deleted file mode 100644
287
index d79173d..0000000
288
--- a/build/lib/ptrack/methods.py
289
+++ /dev/null
290
@@ -1,136 +0,0 @@
291
-import os
292
-import sys
293
-import requests
294
-from rich.console import Console
295
-from rich.progress import Progress, TextColumn, BarColumn, TimeRemainingColumn, FileSizeColumn, Task, DownloadColumn, TimeElapsedColumn
296
-from rich.text import Text
297
-from datetime import timedelta
298
-from humanize import naturalsize
299
-
300
-console = Console()
301
-
302
-
303
-def getTotalSize(srcPaths):
304
-    total_size = 0
305
-    for path in srcPaths:
306
-        if os.path.isfile(path):
307
-            total_size += os.path.getsize(path)
308
-        else:
309
-            for r, d, files in os.walk(path):
310
-                for f in files:
311
-                    fp = os.path.join(r, f)
312
-                    total_size += os.path.getsize(fp)
313
-    return total_size
314
-
315
-
316
-def format_file_size(file_size):
317
-    if file_size >= 1000 ** 4:  # Terabyte
318
-        return f"{round(file_size / (1000 ** 4))} TB"
319
-    elif file_size >= 1000 ** 3:  # Gigabyte
320
-        return f"{round(file_size / (1000 ** 3))} GB"
321
-    elif file_size >= 1000 ** 2:  # Megabyte
322
-        return f"{round(file_size / (1000 ** 2))} MB"
323
-    elif file_size >= 1000:  # Kilobyte
324
-        return f"{round(file_size / 1000)} kB"
325
-    else:  # Byte
326
-        return f"{file_size} bytes"
327
-
328
-
329
-def regular_copy(src, dst, console, task, progress, file_name):
330
-    operation_cancelled = False
331
-    try:
332
-        with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
333
-            while True:
334
-                buf = fsrc.read(1024*1024)
335
-                if not buf or operation_cancelled:
336
-                    break
337
-                fdst.write(buf)
338
-                progress.update(task, advance=len(buf))
339
-                progress.refresh()
340
-
341
-    except KeyboardInterrupt:
342
-        operation_cancelled = True
343
-        progress.stop()
344
-        return "c"
345
-
346
-
347
-def verbose_copy(src, dst, console, current, total_files, file_name):
348
-    operation_cancelled = False
349
-    file_size = os.path.getsize(src)
350
-
351
-    with Progress(
352
-        BarColumn(bar_width=50),
353
-        "[progress.percentage]{task.percentage:>3.0f}%",
354
-        TimeRemainingColumn(),
355
-        "[#ea2a6f][[/#ea2a6f]",
356
-        FileSizeColumn(),
357
-        "[#ea2a6f]/[/#ea2a6f]",
358
-        TextColumn(f"[bold cyan]{format_file_size(file_size)}[/bold cyan]"),
359
-        "[#ea2a6f]][/#ea2a6f]",
360
-        f"({current} of {total_files}) - {file_name}",
361
-        console=console,
362
-        auto_refresh=False
363
-    ) as progress:
364
-        task = progress.add_task("", total=file_size, file_size=format_file_size(file_size))
365
-
366
-        try:
367
-            with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
368
-                while not progress.finished:
369
-                    buf = fsrc.read(1024*1024)
370
-                    if not buf or operation_cancelled:
371
-                        break
372
-                    fdst.write(buf)
373
-                    progress.update(task, advance=len(buf))
374
-                    progress.refresh()
375
-        except KeyboardInterrupt:
376
-            operation_cancelled = True
377
-            progress.stop()
378
-            return "c"
379
-
380
-
381
-def hlp():
382
-    print("""
383
-usage: ptrack [-h] [-v] [-c] [-m] [-d] [-V]
384
-
385
-A simple CLI utility for asthetically tracking progress when copying or moving files.
386
-
387
-options:
388
-  -h, --help      show this help message and exit
389
-  -v, --verbose   verbose output
390
-  -c, --copy      copy files (You can use `ptc` instead of `ptrack -c`)
391
-  -m, --move      move files (You can use `ptm` instead of `ptrack -m`)
392
-  -d, --download  download files (You can use `ptd` instead of `ptrack -d`)
393
-  -V, --version   show program's version number and exit
394
-""")
395
-
396
-
397
-class CustomFileSizeColumn(FileSizeColumn, TimeElapsedColumn):
398
-    def render(self, task):
399
-        completed = task.completed
400
-        total = task.total
401
-        elapsed = task.elapsed
402
-
403
-        if elapsed > 0.0:  # Prevent division by zero
404
-            download_speed = completed / elapsed  # calculate download rate
405
-        else:
406
-            download_speed = 0
407
-
408
-        if total:
409
-            size = Text.assemble(
410
-                (f"{self._human_readable_size(completed)}", "green"),  # completed
411
-                (" / ", "none"),  # separator
412
-                (f"{self._human_readable_size(total)}", "red"),  # total
413
-                (" [", "none"),  # opening square bracket
414
-                (f"{self._human_readable_size(download_speed)}/s", "blue"),  # download rate
415
-                ("]", "none"),  # closing square bracket
416
-            )
417
-        else:
418
-            size = Text(str(self._human_readable_size(completed)))
419
-        return size
420
-
421
-    def _human_readable_size(self, size: int) -> str:
422
-        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
423
-            if abs(size) < 1024.0:
424
-                return f"{size:.1f}{unit}"
425
-            size /= 1024.0
426
-        return f"{size:.1f}PB"
427
diff --git a/dist/ptrack-0.2.4-py3-none-any.whl b/dist/ptrack-0.2.4-py3-none-any.whl
428
deleted file mode 100644
429
index e1a67fa..0000000
430
Binary files a/dist/ptrack-0.2.4-py3-none-any.whl and /dev/null differ
431
diff --git a/dist/ptrack-0.2.4.tar.gz b/dist/ptrack-0.2.4.tar.gz
432
deleted file mode 100644
433
index a79630a..0000000
434
Binary files a/dist/ptrack-0.2.4.tar.gz and /dev/null differ
435
diff --git a/ptrack.egg-info/PKG-INFO b/ptrack.egg-info/PKG-INFO
436
deleted file mode 100644
437
index cc530f3..0000000
438
--- a/ptrack.egg-info/PKG-INFO
439
+++ /dev/null
440
@@ -1,7 +0,0 @@
441
-Metadata-Version: 2.1
442
-Name: ptrack
443
-Version: 0.2.4
444
-Summary: A simple CLI utility for asthetically tracking progress when copying, moving or downloading files.
445
-Author: Connor Etherington
446
-Author-email: [email protected]
447
-License-File: LICENSE
448
diff --git a/ptrack.egg-info/SOURCES.txt b/ptrack.egg-info/SOURCES.txt
449
deleted file mode 100644
450
index 086a784..0000000
451
--- a/ptrack.egg-info/SOURCES.txt
452
+++ /dev/null
453
@@ -1,12 +0,0 @@
454
-LICENSE
455
-README.md
456
-setup.py
457
-ptrack/__init__.py
458
-ptrack/main.py
459
-ptrack/methods.py
460
-ptrack.egg-info/PKG-INFO
461
-ptrack.egg-info/SOURCES.txt
462
-ptrack.egg-info/dependency_links.txt
463
-ptrack.egg-info/entry_points.txt
464
-ptrack.egg-info/requires.txt
465
-ptrack.egg-info/top_level.txt
466
diff --git a/ptrack.egg-info/dependency_links.txt b/ptrack.egg-info/dependency_links.txt
467
deleted file mode 100644
468
index 8b13789..0000000
469
--- a/ptrack.egg-info/dependency_links.txt
470
+++ /dev/null
471
@@ -1 +0,0 @@
472
-
473
diff --git a/ptrack.egg-info/entry_points.txt b/ptrack.egg-info/entry_points.txt
474
deleted file mode 100644
475
index ea851b3..0000000
476
--- a/ptrack.egg-info/entry_points.txt
477
+++ /dev/null
478
@@ -1,5 +0,0 @@
479
-[console_scripts]
480
-ptc = ptrack.main:copy
481
-ptd = ptrack.main:download
482
-ptm = ptrack.main:move
483
-ptrack = ptrack.main:main
484
diff --git a/ptrack.egg-info/requires.txt b/ptrack.egg-info/requires.txt
485
deleted file mode 100644
486
index d19a378..0000000
487
--- a/ptrack.egg-info/requires.txt
488
+++ /dev/null
489
@@ -1,6 +0,0 @@
490
-rich
491
-argparse
492
-requests
493
-validators
494
-setuptools
495
-humanize
496
diff --git a/ptrack.egg-info/top_level.txt b/ptrack.egg-info/top_level.txt
497
deleted file mode 100644
498
index c003217..0000000
499
--- a/ptrack.egg-info/top_level.txt
500
+++ /dev/null
501
@@ -1 +0,0 @@
502
-ptrack
503
diff --git a/ptrack/__init__.py b/ptrack/__init__.py
504
index 0e7f0c7..a329509 100644
505
--- a/ptrack/__init__.py
506
+++ b/ptrack/__init__.py
507
@@ -1,5 +1,5 @@
508
 import argparse
509
-version="0.2.4"
510
+version="0.2.5"
511
 
512
 parser = argparse.ArgumentParser(description='A simple CLI utility for asthetically tracking progress when copying or moving files.')
513
 parser.add_argument('-v', '--verbose', action='store_true', help='verbose output')
514
diff --git a/ptrack/main.py b/ptrack/main.py
515
index 48419be..a0b26dc 100644
516
--- a/ptrack/main.py
517
+++ b/ptrack/main.py
518
@@ -45,6 +45,7 @@ def run(process):
519
 
520
     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))
521
     total_size = getTotalSize(srcPaths)
522
+    destination_path = os.path.join(dst_dir, os.path.basename(srcPaths[0]) if not new_name else new_name)
523
 
524
     current_file = 1
525
 
526
@@ -86,29 +87,34 @@ def run(process):
527
             "[#ea2a6f]/[/#ea2a6f]",
528
             TextColumn("[bold cyan]{task.fields[total_size]}[/bold cyan]"),
529
             "[#ea2a6f]][/#ea2a6f]",
530
+            TextColumn("-[bold yellow] {task.fields[current_file_name]}[/bold yellow]"),
531
             console=console,
532
             auto_refresh=False
533
         ) as progress:
534
-            task = progress.add_task("", total=total_size, total_size=format_file_size(total_size))
535
-
536
-            for src_path in srcPaths:
537
-                if os.path.isfile(src_path):
538
-                    dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name)
539
-                    terminate = regular_copy(src_path, dst_file_path, console, task, progress, file_name=os.path.basename(src_path))
540
-                    if terminate == 'c':
541
-                        console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
542
-                        sys.exit(1)
543
-                else:
544
-                    for root, dirs, files in os.walk(src_path):
545
-                        for file in files:
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 = regular_copy(src_file_path, dst_file_path, console, task, progress, file_name=file)
551
-                            if terminate == 'c':
552
-                                console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
553
-                                sys.exit(1)
554
+            task = progress.add_task("", total=total_size, total_size=format_file_size(total_size), current_file_name="Initializing...")
555
+
556
+            try:
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
+                        progress.update(task, current_file_name=os.path.basename(src_path), refresh=True)  # Force refresh
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
+                    else:
566
+                        for root, dirs, files in os.walk(src_path):
567
+                            for file in files:
568
+                                src_file_path = os.path.join(root, file)
569
+                                relative_path = os.path.relpath(src_file_path, start=src_path)
570
+                                dst_file_path = os.path.join(dst_dir, os.path.basename(src_path) if not new_name else new_name, relative_path)
571
+                                os.makedirs(os.path.dirname(dst_file_path), exist_ok=True)
572
+                                progress.update(task, current_file_name=file, refresh=True)  # Force refresh
573
+                                regular_copy(src_file_path, dst_file_path, console, task, progress, file_name=file)
574
+
575
+            except KeyboardInterrupt:
576
+                console.print("\n[bold red]\[-][/bold red][bold white] Operation cancelled by user.[/bold white]\n")
577
+                sys.exit(1)
578
 
579
     return srcPaths
580
 
581
diff --git a/ptrack/methods.py b/ptrack/methods.py
582
index d79173d..2e9677e 100644
583
--- a/ptrack/methods.py
584
+++ b/ptrack/methods.py
585
@@ -8,6 +8,7 @@ from datetime import timedelta
586
 from humanize import naturalsize
587
 
588
 console = Console()
589
+operation_cancelled = False
590
 
591
 
592
 def getTotalSize(srcPaths):
593
@@ -36,12 +37,15 @@ def format_file_size(file_size):
594
         return f"{file_size} bytes"
595
 
596
 
597
+
598
 def regular_copy(src, dst, console, task, progress, file_name):
599
-    operation_cancelled = False
600
+
601
+    global operation_cancelled
602
+
603
     try:
604
         with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
605
             while True:
606
-                buf = fsrc.read(1024*1024)
607
+                buf = fsrc.read(1024 * 128)  # Reduced buffer size for more frequent checks
608
                 if not buf or operation_cancelled:
609
                     break
610
                 fdst.write(buf)
611
diff --git a/recipe/meta.yaml b/recipe/meta.yaml
612
index 5bda8cf..62dc45a 100644
613
--- a/recipe/meta.yaml
614
+++ b/recipe/meta.yaml
615
@@ -1,6 +1,6 @@
616
 package:
617
   name: ptrack
618
-  version: 0.2.4
619
+  version: 0.2.5
620
 
621
 source:
622
   path: ..
623
diff --git a/setup.py b/setup.py
624
index 3bd3c2f..2c8aa5c 100644
625
--- a/setup.py
626
+++ b/setup.py
627
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
628
 
629
 setup(
630
     name='ptrack',
631
-    version="0.2.4",
632
+    version="0.2.5",
633
     description='A simple CLI utility for asthetically tracking progress when copying, moving or downloading files.',
634
     author='Connor Etherington',
635
     author_email='[email protected]',