ccfx 1.0.8__tar.gz → 1.0.9__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: ccfx
3
- Version: 1.0.8
3
+ Version: 1.0.9
4
4
  Summary: This package simplifies regular common actions for quick prototyping in a user friendly way
5
5
  Author-email: Celray James CHAWANDA <celray@chawanda.com>
6
6
  License-Expression: MIT
@@ -479,9 +479,9 @@ def alert(message:str, server:str = "http://ntfy.sh", topic:str = "pythonAlerts"
479
479
  return: True if the alert was sent successfully, False otherwise
480
480
  '''
481
481
  print(message) if printIt else None; header_data = {}
482
- if not messageTitle is None: header_data["Title"] = messageTitle
483
- if not priority is None: header_data["Priority"] = priority
484
- if not len(tags) == 0: header_data["Tags"] = ",".join(tags)
482
+ if not messageTitle is None: header_data["Title"] = str(messageTitle).replace("\r"," ").replace("\n"," ")
483
+ if not priority is None: header_data["Priority"] = str(int(priority))
484
+ if not len(tags) == 0: header_data["Tags"] = ",".join(map(str, tags))
485
485
 
486
486
  try:
487
487
  if v: print(f"sending alert to {server}/{topic}")
@@ -517,6 +517,7 @@ def deletePath(path:str, v:bool = False) -> bool:
517
517
  if v:
518
518
  print(f'! {path} does not exist')
519
519
  deleted = False
520
+ return deleted
520
521
 
521
522
 
522
523
  def downloadChunk(url: str, start: int, end: int, path: str) -> None:
@@ -528,6 +529,46 @@ def downloadChunk(url: str, start: int, end: int, path: str) -> None:
528
529
  f.write(chunk)
529
530
 
530
531
 
532
+ def correctFisheye(inputFile: str, outputFile: str = '',
533
+ k1: float = -0.1, k2: float = 0.05,
534
+ cx: float = 0.5, cy: float = 0.5,
535
+ crf: int = 20) -> str:
536
+ """
537
+ Correct fisheye distortion in a video and save as MP4.
538
+
539
+ Args:
540
+ inputFile (str): Path to the input video (any format).
541
+ outputFile (str, optional): Path for the corrected MP4. If None, auto-creates.
542
+ k1, k2 (float): Lens distortion coefficients.
543
+ cx, cy (float): Optical center (0.5 = image center).
544
+ crf (int): Constant Rate Factor (lower = better quality, larger file).
545
+
546
+ Returns:
547
+ str: Path to the corrected MP4 file.
548
+ """
549
+ if not os.path.exists(inputFile):
550
+ raise FileNotFoundError(f"Input file not found: {inputFile}")
551
+
552
+ # Default output path
553
+ if outputFile == '':
554
+ base, _ = os.path.splitext(inputFile)
555
+ outputFile = f"{base}_corrected.mp4"
556
+
557
+ cmd = [
558
+ "ffmpeg", "-hide_banner", "-loglevel", "error", "-stats",
559
+ "-i", inputFile,
560
+ "-vf", f"lenscorrection=cx={cx}:cy={cy}:k1={k1}:k2={k2}",
561
+ "-c:v", "libx264", "-preset", "slow", f"-crf", str(crf),
562
+ "-pix_fmt", "yuv420p",
563
+ "-c:a", "aac", "-b:a", "192k",
564
+ "-movflags", "+faststart",
565
+ outputFile
566
+ ]
567
+
568
+ subprocess.run(cmd, check=True)
569
+ return outputFile
570
+
571
+
531
572
  def formatStringBlock(input_str: str, max_chars: int = 70) -> str:
532
573
  '''
533
574
  This function takes a string and formats it into a block of text
@@ -558,7 +599,6 @@ def formatStringBlock(input_str: str, max_chars: int = 70) -> str:
558
599
 
559
600
 
560
601
 
561
-
562
602
  def downloadFile(url: str, save_path: str, exists_action: str = 'resume', num_connections: int = 5, v: bool = False) -> None:
563
603
  if v:
564
604
  print(f"\ndownloading {url}")
@@ -573,13 +613,17 @@ def downloadFile(url: str, save_path: str, exists_action: str = 'resume', num_co
573
613
  if os.path.exists(save_fname):
574
614
  if exists_action == 'skip':
575
615
  if v:
576
- print(f"File exists, skipping: {save_fname}")
616
+ print(f"file exists, skipping: {save_fname}")
577
617
  return
578
618
  elif exists_action == 'overwrite':
579
619
  os.remove(save_fname)
580
620
  # 'resume' is handled below
581
621
 
582
- # Get file size
622
+ # Get file size (suppress urllib3 warnings when v=False)
623
+ import urllib3
624
+ if not v:
625
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
626
+
583
627
  response = requests.head(url)
584
628
  file_size = int(response.headers.get('content-length', 0))
585
629
 
@@ -589,7 +633,7 @@ def downloadFile(url: str, save_path: str, exists_action: str = 'resume', num_co
589
633
  initial_pos = os.path.getsize(save_fname)
590
634
  if initial_pos >= file_size:
591
635
  if v:
592
- print(f"File already completed: {save_fname}")
636
+ print(f"file already completed: {save_fname}")
593
637
  return
594
638
 
595
639
  # Calculate chunk sizes
@@ -609,14 +653,22 @@ def downloadFile(url: str, save_path: str, exists_action: str = 'resume', num_co
609
653
  executor.submit(downloadChunk, url, start, end, temp_files[i])
610
654
  )
611
655
 
612
- # Wait for all downloads to complete with progress bar
613
- with tqdm(total=file_size-initial_pos, initial=initial_pos, unit='B',
614
- unit_scale=True, desc=fname) as pbar:
615
- completed = initial_pos
616
- while completed < file_size:
656
+ # Wait for all downloads to complete with progress bar (conditionally show progress)
657
+ if v:
658
+ with tqdm(total=file_size-initial_pos, initial=initial_pos, unit='B',
659
+ unit_scale=True, desc=fname) as pbar:
660
+ completed = initial_pos
661
+ while completed < file_size:
662
+ current = sum(os.path.getsize(f) for f in temp_files if os.path.exists(f))
663
+ pbar.update(current - completed)
664
+ completed = current
665
+ else:
666
+ # Wait silently without progress bar
667
+ while True:
617
668
  current = sum(os.path.getsize(f) for f in temp_files if os.path.exists(f))
618
- pbar.update(current - completed)
619
- completed = current
669
+ if current >= file_size - initial_pos:
670
+ break
671
+ time.sleep(0.1)
620
672
 
621
673
  # Merge chunks
622
674
  with open(save_fname, 'ab' if initial_pos > 0 else 'wb') as outfile:
@@ -627,6 +679,7 @@ def downloadFile(url: str, save_path: str, exists_action: str = 'resume', num_co
627
679
  os.remove(temp_file)
628
680
 
629
681
 
682
+
630
683
  def mergeRasterTiles(tileList:list, outFile:str) -> str:
631
684
  '''
632
685
  Merge raster tiles into one raster file
@@ -1588,9 +1641,9 @@ def showProgress(count: int, end: int, message: str, barLength: int = 100) -> No
1588
1641
  percentStr = f'{percent:03.1f}'
1589
1642
  filled = int(barLength * count / end)
1590
1643
  bar = '█' * filled + '░' * (barLength - filled)
1591
- print(f'\r{message} |{bar}| {percent}% [{count}/{end}]', end='', flush=True)
1644
+ print(f'\r{message} |{bar}| {percentStr}% [{count}/{end}]', end='', flush=True)
1592
1645
  if count == end:
1593
- print(f'\r{message} |{bar}| {percent}% [{count}/{end}] ', end='', flush=True)
1646
+ print(f'\r{message} |{bar}| {percentStr}% [{count}/{end}] ', end='', flush=True)
1594
1647
  print()
1595
1648
 
1596
1649
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ccfx
3
- Version: 1.0.8
3
+ Version: 1.0.9
4
4
  Summary: This package simplifies regular common actions for quick prototyping in a user friendly way
5
5
  Author-email: Celray James CHAWANDA <celray@chawanda.com>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ccfx"
7
- version = "1.0.8"
7
+ version = "1.0.9"
8
8
  description = "This package simplifies regular common actions for quick prototyping in a user friendly way"
9
9
  readme = "README.md"
10
10
  license = "MIT"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes