ai-screenshooter 1.7.0__tar.gz → 1.7.1__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: ai-screenshooter
3
- Version: 1.7.0
3
+ Version: 1.7.1
4
4
  Summary: A CLI tool to capture and send AI-powered screenshots
5
5
  Home-page: https://github.com/tech4vision/ai-screenshoter
6
6
  Author: Last Shot AI
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ai-screenshooter
3
- Version: 1.7.0
3
+ Version: 1.7.1
4
4
  Summary: A CLI tool to capture and send AI-powered screenshots
5
5
  Home-page: https://github.com/tech4vision/ai-screenshoter
6
6
  Author: Last Shot AI
@@ -1,4 +1,5 @@
1
1
  import argparse
2
+ import json
2
3
  import os
3
4
  import sys
4
5
  import signal
@@ -18,6 +19,7 @@ from pynput import keyboard
18
19
  # Constants
19
20
  PID_FILE = Path.home() / ".ai-screenshooter.pid"
20
21
  LOG_FILE = Path.home() / ".ai-screenshooter.log"
22
+ META_FILE = Path.home() / ".ai-screenshooter.meta.json"
21
23
  SCREENSHOT_DIR = Path.home() / ".ai-screenshooter" / "screenshots"
22
24
  AUDIO_DIR = Path.home() / ".ai-screenshooter" / "audio"
23
25
  TIMEOUT_SECONDS = 5 * 60 * 60 # 5 hours
@@ -97,6 +99,31 @@ def cleanup_pid_file():
97
99
  PID_FILE.unlink()
98
100
  except Exception:
99
101
  pass
102
+ try:
103
+ if META_FILE.exists():
104
+ META_FILE.unlink()
105
+ except Exception:
106
+ pass
107
+
108
+
109
+ def write_meta_file(server_mode, server_url):
110
+ """Write process metadata for status command."""
111
+ meta = {
112
+ "started_at": time.time(),
113
+ "server_mode": server_mode,
114
+ "server_url": server_url,
115
+ }
116
+ META_FILE.write_text(json.dumps(meta))
117
+
118
+
119
+ def read_meta_file():
120
+ """Read process metadata, return None if invalid."""
121
+ if not META_FILE.exists():
122
+ return None
123
+ try:
124
+ return json.loads(META_FILE.read_text())
125
+ except (ValueError, IOError):
126
+ return None
100
127
 
101
128
 
102
129
  # ============ Process Management ============
@@ -482,11 +509,14 @@ def send_transcribed_text(text):
482
509
  def on_press(key):
483
510
  global last_esc_time, is_recording
484
511
 
485
- current_keys.add(key)
486
-
487
512
  try:
488
513
  # Double-tap ESC detection for voice recording
489
514
  if key == keyboard.Key.esc:
515
+ # Ignore repeated key events from holding ESC
516
+ if keyboard.Key.esc in current_keys:
517
+ return
518
+ current_keys.add(key)
519
+
490
520
  current_time = time.time()
491
521
  time_since_last = current_time - last_esc_time
492
522
 
@@ -496,8 +526,12 @@ def on_press(key):
496
526
 
497
527
  last_esc_time = current_time
498
528
 
529
+ # Track non-ESC keys for combo detection
530
+ else:
531
+ current_keys.add(key)
532
+
499
533
  # Other hotkeys (ESC + arrow keys)
500
- elif key == keyboard.Key.down and keyboard.Key.esc in current_keys:
534
+ if key == keyboard.Key.down and keyboard.Key.esc in current_keys:
501
535
  logger.info("Capturing screenshot...")
502
536
  capture_screenshot()
503
537
  elif key == keyboard.Key.up and keyboard.Key.esc in current_keys:
@@ -530,19 +564,20 @@ def cmd_start(args):
530
564
  """Handle the start command."""
531
565
  global API_TOKEN, API_URL
532
566
 
533
- # If --background flag, spawn a new process and exit
534
- if args.background:
535
- print("Starting in background mode...")
567
+ is_daemon = getattr(args, 'daemon', False)
568
+
569
+ # Kill any existing instance (unless this is the daemon subprocess itself)
570
+ if not is_daemon:
536
571
  killed = kill_existing_process()
537
572
  if killed:
538
- print("Killed existing instance.")
573
+ print("Replaced existing instance.")
539
574
 
575
+ # If --background flag, spawn a new process and exit
576
+ if args.background:
577
+ print("Starting in background mode...")
540
578
  start_background_process(args.token, args.local)
541
579
  return
542
580
 
543
- # If --daemon flag (internal), this is the actual daemon process
544
- is_daemon = getattr(args, 'daemon', False)
545
-
546
581
  if is_daemon:
547
582
  # Write PID file
548
583
  write_pid_file()
@@ -565,6 +600,10 @@ def cmd_start(args):
565
600
  API_URL = LOCAL_URL if args.local else PROD_URL
566
601
 
567
602
  server_mode = "LOCAL" if args.local else "PRODUCTION"
603
+
604
+ # Write metadata for status command
605
+ write_meta_file(server_mode, API_URL)
606
+
568
607
  logger.info("AI Screenshot CLI started.")
569
608
  logger.info(f"Server: {server_mode} ({API_URL})")
570
609
  logger.info("Press ESC + Down to capture a screenshot.")
@@ -584,11 +623,38 @@ def cmd_status(args):
584
623
  pid = get_pid_from_file()
585
624
  if pid and is_process_running(pid):
586
625
  print(f"ai-screenshooter is running (PID: {pid})")
626
+
627
+ meta = read_meta_file()
628
+ if meta:
629
+ # Uptime
630
+ elapsed = time.time() - meta.get("started_at", time.time())
631
+ hours, remainder = divmod(int(elapsed), 3600)
632
+ minutes, seconds = divmod(remainder, 60)
633
+ print(f" Uptime: {hours}h {minutes}m {seconds}s")
634
+
635
+ # Time remaining
636
+ remaining = TIMEOUT_SECONDS - elapsed
637
+ if remaining > 0:
638
+ rh, rr = divmod(int(remaining), 3600)
639
+ rm, rs = divmod(rr, 60)
640
+ print(f" Expires: {rh}h {rm}m {rs}s remaining")
641
+
642
+ # Server
643
+ print(f" Server: {meta.get('server_mode', 'UNKNOWN')} ({meta.get('server_url', '')})")
644
+
645
+ print()
646
+ print(" Listening for hotkeys:")
647
+ print(" ESC + Down Capture screenshot")
648
+ print(" ESC + Up Send all screenshots")
649
+ print(" ESC + Right Send clipboard text to Code tab")
650
+ print(" Double-tap ESC Record voice, transcribe and send")
651
+
587
652
  return 0
588
653
  else:
589
654
  print("ai-screenshooter is not running")
590
655
  if PID_FILE.exists():
591
- print(f"(stale PID file exists at {PID_FILE})")
656
+ print(f"(stale PID file found, cleaning up)")
657
+ cleanup_pid_file()
592
658
  return 1
593
659
 
594
660
 
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="ai-screenshooter",
5
- version="1.7.0",
5
+ version="1.7.1",
6
6
  packages=find_packages(),
7
7
  py_modules=["ai_screenshot"],
8
8
  install_requires=[