desk-awake 1.0.0__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.
- desk_awake-1.0.0/PKG-INFO +107 -0
- desk_awake-1.0.0/README.md +92 -0
- desk_awake-1.0.0/pyproject.toml +32 -0
- desk_awake-1.0.0/setup.cfg +4 -0
- desk_awake-1.0.0/src/desk_awake/__init__.py +3 -0
- desk_awake-1.0.0/src/desk_awake/__main__.py +5 -0
- desk_awake-1.0.0/src/desk_awake/cli.py +80 -0
- desk_awake-1.0.0/src/desk_awake/core.py +203 -0
- desk_awake-1.0.0/src/desk_awake.egg-info/PKG-INFO +107 -0
- desk_awake-1.0.0/src/desk_awake.egg-info/SOURCES.txt +12 -0
- desk_awake-1.0.0/src/desk_awake.egg-info/dependency_links.txt +1 -0
- desk_awake-1.0.0/src/desk_awake.egg-info/entry_points.txt +2 -0
- desk_awake-1.0.0/src/desk_awake.egg-info/requires.txt +7 -0
- desk_awake-1.0.0/src/desk_awake.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: desk-awake
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Cross-platform idle activity simulator with AnyDesk integration
|
|
5
|
+
Author: Abhinav Hudda
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: pynput>=1.7.0
|
|
10
|
+
Provides-Extra: mac
|
|
11
|
+
Requires-Dist: pyobjc-core>=9.0; extra == "mac"
|
|
12
|
+
Requires-Dist: pyobjc-framework-ApplicationServices>=9.0; extra == "mac"
|
|
13
|
+
Requires-Dist: pyobjc-framework-Cocoa>=9.0; extra == "mac"
|
|
14
|
+
Requires-Dist: pyobjc-framework-Quartz>=9.0; extra == "mac"
|
|
15
|
+
|
|
16
|
+
# Desk Awake
|
|
17
|
+
|
|
18
|
+
Cross-platform idle activity simulator. Keeps your session active by generating mouse movements and keyboard actions until a specified time.
|
|
19
|
+
|
|
20
|
+
Auto-detects the OS and uses appropriate modifier keys (`Cmd` on macOS, `Ctrl` on Linux/Windows) and system commands.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install desk-awake
|
|
26
|
+
|
|
27
|
+
# On macOS, include the optional mac dependencies
|
|
28
|
+
pip install "desk-awake[mac]"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
Once installed, the `desk-awake` command is available globally:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Run until a specific time (24h format)
|
|
37
|
+
desk-awake --until "18:30"
|
|
38
|
+
|
|
39
|
+
# Run until a specific date and time
|
|
40
|
+
desk-awake --until "2025-01-15 17:00"
|
|
41
|
+
|
|
42
|
+
# Short flag works too
|
|
43
|
+
desk-awake -u "18:30"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Multi-day mode
|
|
47
|
+
|
|
48
|
+
Run daily on a schedule until a specific end date:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Run every day from 09:00 to 18:30, until June 15th
|
|
52
|
+
desk-awake -u "18:30" --start "09:00" --end-date "2026-06-15"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Exit behavior flags
|
|
56
|
+
|
|
57
|
+
| Flag | Description |
|
|
58
|
+
|------|-------------|
|
|
59
|
+
| `--close-anydesk` | Close AnyDesk when done (default) |
|
|
60
|
+
| `--no-close-anydesk` | Don't close AnyDesk when done |
|
|
61
|
+
| `--sleep` | Put machine to sleep when done |
|
|
62
|
+
| `--no-sleep` | Don't sleep when done |
|
|
63
|
+
|
|
64
|
+
### OS-specific defaults
|
|
65
|
+
|
|
66
|
+
| OS | Close AnyDesk | Sleep |
|
|
67
|
+
|----|---------------|-------|
|
|
68
|
+
| macOS | ✅ | ✅ |
|
|
69
|
+
| Linux | ✅ | ❌ |
|
|
70
|
+
| Windows | ✅ | ✅ |
|
|
71
|
+
|
|
72
|
+
Override any default with the flags above.
|
|
73
|
+
|
|
74
|
+
### Examples
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Ubuntu: run until 6:30 PM, close AnyDesk, no sleep (default)
|
|
78
|
+
desk-awake -u "18:30"
|
|
79
|
+
|
|
80
|
+
# macOS: run until 6:30 PM, close AnyDesk, sleep (default)
|
|
81
|
+
desk-awake -u "18:30"
|
|
82
|
+
|
|
83
|
+
# macOS: skip sleep
|
|
84
|
+
desk-awake -u "18:30" --no-sleep
|
|
85
|
+
|
|
86
|
+
# Linux: force sleep too
|
|
87
|
+
desk-awake -u "18:30" --sleep
|
|
88
|
+
|
|
89
|
+
# Multi-day: run 09:00–18:30 daily until a date
|
|
90
|
+
desk-awake -u "18:30" -s "09:00" -e "2026-06-15"
|
|
91
|
+
|
|
92
|
+
# Keep everything running, don't close anything
|
|
93
|
+
desk-awake -u "18:30" --no-close-anydesk --no-sleep
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Running without installing
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
python -m desk_awake --until "18:30"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Requirements
|
|
103
|
+
|
|
104
|
+
- Python 3.8+
|
|
105
|
+
- `pynput` (installed automatically)
|
|
106
|
+
- On macOS: `pyobjc` packages (install with `pip install "desk-awake[mac]"`)
|
|
107
|
+
- On Linux: may need `xdotool` or X11 libs depending on your display server
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Desk Awake
|
|
2
|
+
|
|
3
|
+
Cross-platform idle activity simulator. Keeps your session active by generating mouse movements and keyboard actions until a specified time.
|
|
4
|
+
|
|
5
|
+
Auto-detects the OS and uses appropriate modifier keys (`Cmd` on macOS, `Ctrl` on Linux/Windows) and system commands.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install desk-awake
|
|
11
|
+
|
|
12
|
+
# On macOS, include the optional mac dependencies
|
|
13
|
+
pip install "desk-awake[mac]"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
Once installed, the `desk-awake` command is available globally:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Run until a specific time (24h format)
|
|
22
|
+
desk-awake --until "18:30"
|
|
23
|
+
|
|
24
|
+
# Run until a specific date and time
|
|
25
|
+
desk-awake --until "2025-01-15 17:00"
|
|
26
|
+
|
|
27
|
+
# Short flag works too
|
|
28
|
+
desk-awake -u "18:30"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Multi-day mode
|
|
32
|
+
|
|
33
|
+
Run daily on a schedule until a specific end date:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Run every day from 09:00 to 18:30, until June 15th
|
|
37
|
+
desk-awake -u "18:30" --start "09:00" --end-date "2026-06-15"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Exit behavior flags
|
|
41
|
+
|
|
42
|
+
| Flag | Description |
|
|
43
|
+
|------|-------------|
|
|
44
|
+
| `--close-anydesk` | Close AnyDesk when done (default) |
|
|
45
|
+
| `--no-close-anydesk` | Don't close AnyDesk when done |
|
|
46
|
+
| `--sleep` | Put machine to sleep when done |
|
|
47
|
+
| `--no-sleep` | Don't sleep when done |
|
|
48
|
+
|
|
49
|
+
### OS-specific defaults
|
|
50
|
+
|
|
51
|
+
| OS | Close AnyDesk | Sleep |
|
|
52
|
+
|----|---------------|-------|
|
|
53
|
+
| macOS | ✅ | ✅ |
|
|
54
|
+
| Linux | ✅ | ❌ |
|
|
55
|
+
| Windows | ✅ | ✅ |
|
|
56
|
+
|
|
57
|
+
Override any default with the flags above.
|
|
58
|
+
|
|
59
|
+
### Examples
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Ubuntu: run until 6:30 PM, close AnyDesk, no sleep (default)
|
|
63
|
+
desk-awake -u "18:30"
|
|
64
|
+
|
|
65
|
+
# macOS: run until 6:30 PM, close AnyDesk, sleep (default)
|
|
66
|
+
desk-awake -u "18:30"
|
|
67
|
+
|
|
68
|
+
# macOS: skip sleep
|
|
69
|
+
desk-awake -u "18:30" --no-sleep
|
|
70
|
+
|
|
71
|
+
# Linux: force sleep too
|
|
72
|
+
desk-awake -u "18:30" --sleep
|
|
73
|
+
|
|
74
|
+
# Multi-day: run 09:00–18:30 daily until a date
|
|
75
|
+
desk-awake -u "18:30" -s "09:00" -e "2026-06-15"
|
|
76
|
+
|
|
77
|
+
# Keep everything running, don't close anything
|
|
78
|
+
desk-awake -u "18:30" --no-close-anydesk --no-sleep
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Running without installing
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
python -m desk_awake --until "18:30"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Requirements
|
|
88
|
+
|
|
89
|
+
- Python 3.8+
|
|
90
|
+
- `pynput` (installed automatically)
|
|
91
|
+
- On macOS: `pyobjc` packages (install with `pip install "desk-awake[mac]"`)
|
|
92
|
+
- On Linux: may need `xdotool` or X11 libs depending on your display server
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "desk-awake"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Cross-platform idle activity simulator with AnyDesk integration"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Abhinav Hudda"}
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
dependencies = [
|
|
17
|
+
"pynput>=1.7.0",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
mac = [
|
|
22
|
+
"pyobjc-core>=9.0",
|
|
23
|
+
"pyobjc-framework-ApplicationServices>=9.0",
|
|
24
|
+
"pyobjc-framework-Cocoa>=9.0",
|
|
25
|
+
"pyobjc-framework-Quartz>=9.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
desk-awake = "desk_awake.cli:main"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["src"]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
from .core import CURRENT_OS, parse_datetime, parse_date, perform_actions
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
"""CLI entry point for desk-awake."""
|
|
9
|
+
parser = argparse.ArgumentParser(
|
|
10
|
+
prog='desk-awake',
|
|
11
|
+
description='Simulate idle activity until a specified time. '
|
|
12
|
+
'Auto-detects OS and uses appropriate keys/commands.',
|
|
13
|
+
epilog='Defaults: On macOS — closes AnyDesk and sleeps. '
|
|
14
|
+
'On Linux — closes AnyDesk only (no sleep). '
|
|
15
|
+
'Use flags to override.'
|
|
16
|
+
)
|
|
17
|
+
parser.add_argument('--until', '-u', type=str, required=True,
|
|
18
|
+
help='Daily stop time in format "YYYY-MM-DD HH:MM" or "HH:MM" (24h format)')
|
|
19
|
+
parser.add_argument('--end-date', '-e', type=str, default=None,
|
|
20
|
+
help='Run daily until this date (format: YYYY-MM-DD). '
|
|
21
|
+
'Script repeats each day from --start to --until time.')
|
|
22
|
+
parser.add_argument('--start', '-s', type=str, default=None,
|
|
23
|
+
help='Daily start time in "HH:MM" format (used with --end-date). '
|
|
24
|
+
'Defaults to now if not specified.')
|
|
25
|
+
parser.add_argument('--close-anydesk', action='store_true', dest='close_anydesk', default=None,
|
|
26
|
+
help='Close AnyDesk when done')
|
|
27
|
+
parser.add_argument('--no-close-anydesk', action='store_false', dest='close_anydesk',
|
|
28
|
+
help='Do NOT close AnyDesk when done')
|
|
29
|
+
parser.add_argument('--sleep', action='store_true', dest='sleep', default=None,
|
|
30
|
+
help='Put machine to sleep when done')
|
|
31
|
+
parser.add_argument('--no-sleep', action='store_false', dest='sleep',
|
|
32
|
+
help='Do NOT put machine to sleep when done')
|
|
33
|
+
|
|
34
|
+
args = parser.parse_args()
|
|
35
|
+
|
|
36
|
+
# Apply OS-specific defaults when user hasn't explicitly set a flag
|
|
37
|
+
if args.close_anydesk is None:
|
|
38
|
+
close_anydesk_on_exit = True # Default: always close AnyDesk
|
|
39
|
+
else:
|
|
40
|
+
close_anydesk_on_exit = args.close_anydesk
|
|
41
|
+
|
|
42
|
+
if args.sleep is None:
|
|
43
|
+
# macOS/Windows: sleep by default. Linux: don't sleep by default.
|
|
44
|
+
sleep_on_exit = CURRENT_OS != "linux"
|
|
45
|
+
else:
|
|
46
|
+
sleep_on_exit = args.sleep
|
|
47
|
+
|
|
48
|
+
# Parse end date if provided
|
|
49
|
+
end_date = None
|
|
50
|
+
if args.end_date:
|
|
51
|
+
try:
|
|
52
|
+
end_date = parse_date(args.end_date)
|
|
53
|
+
except ValueError as e:
|
|
54
|
+
print(f"Error: {e}")
|
|
55
|
+
return 1
|
|
56
|
+
|
|
57
|
+
from datetime import date as date_cls
|
|
58
|
+
if end_date < date_cls.today():
|
|
59
|
+
print("Error: --end-date must be today or in the future!")
|
|
60
|
+
return 1
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
stop_time = parse_datetime(args.until)
|
|
64
|
+
|
|
65
|
+
# For single-run mode (no end-date), stop_time must be in the future
|
|
66
|
+
if not end_date and stop_time <= datetime.now():
|
|
67
|
+
print("Error: Stop time must be in the future!")
|
|
68
|
+
return 1
|
|
69
|
+
|
|
70
|
+
print(f"Starting activity simulation: ~50 keys/min, ~60 mouse movements/min")
|
|
71
|
+
perform_actions(stop_time, close_anydesk_on_exit, sleep_on_exit,
|
|
72
|
+
end_date=end_date, start_time_str=args.start)
|
|
73
|
+
return 0
|
|
74
|
+
except ValueError as e:
|
|
75
|
+
print(f"Error: {e}")
|
|
76
|
+
return 1
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import subprocess
|
|
3
|
+
import random
|
|
4
|
+
import platform
|
|
5
|
+
from datetime import datetime, timedelta, date
|
|
6
|
+
from pynput.mouse import Controller as MouseController
|
|
7
|
+
from pynput.keyboard import Controller as KeyboardController, Key
|
|
8
|
+
|
|
9
|
+
# Initialize pynput controllers
|
|
10
|
+
mouse = MouseController()
|
|
11
|
+
keyboard = KeyboardController()
|
|
12
|
+
|
|
13
|
+
# Detect OS
|
|
14
|
+
CURRENT_OS = platform.system().lower() # 'darwin' for macOS, 'linux' for Ubuntu/Linux, 'windows' for Windows
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_modifier_key():
|
|
18
|
+
"""Return the appropriate modifier key for the current OS."""
|
|
19
|
+
if CURRENT_OS == "darwin":
|
|
20
|
+
return Key.cmd
|
|
21
|
+
else:
|
|
22
|
+
return Key.ctrl
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def close_anydesk():
|
|
26
|
+
"""Close AnyDesk based on the current OS."""
|
|
27
|
+
try:
|
|
28
|
+
if CURRENT_OS == "darwin":
|
|
29
|
+
subprocess.run(['osascript', '-e', 'tell application "AnyDesk" to quit'], check=False)
|
|
30
|
+
subprocess.run(['pkill', '-f', 'AnyDesk'], check=False)
|
|
31
|
+
elif CURRENT_OS == "linux":
|
|
32
|
+
subprocess.run(['pkill', '-f', 'anydesk'], check=False)
|
|
33
|
+
elif CURRENT_OS == "windows":
|
|
34
|
+
subprocess.run(['taskkill', '/F', '/IM', 'AnyDesk.exe'], check=False)
|
|
35
|
+
print("AnyDesk closed.")
|
|
36
|
+
except Exception as e:
|
|
37
|
+
print(f"Error closing AnyDesk: {e}")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def put_to_sleep():
|
|
41
|
+
"""Put the machine to sleep based on the current OS."""
|
|
42
|
+
try:
|
|
43
|
+
if CURRENT_OS == "darwin":
|
|
44
|
+
subprocess.run(['osascript', '-e', 'tell application "System Events" to sleep'], check=False)
|
|
45
|
+
print("Mac is going to sleep...")
|
|
46
|
+
elif CURRENT_OS == "linux":
|
|
47
|
+
subprocess.run(['systemctl', 'suspend'], check=False)
|
|
48
|
+
print("Linux is going to sleep...")
|
|
49
|
+
elif CURRENT_OS == "windows":
|
|
50
|
+
subprocess.run(['rundll32.exe', 'powrprof.dll,SetSuspendState', '0,1,0'], check=False)
|
|
51
|
+
print("Windows is going to sleep...")
|
|
52
|
+
except Exception as e:
|
|
53
|
+
print(f"Error putting machine to sleep: {e}")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def parse_datetime(datetime_str):
|
|
57
|
+
"""Parse datetime string in format YYYY-MM-DD HH:MM or HH:MM."""
|
|
58
|
+
try:
|
|
59
|
+
return datetime.strptime(datetime_str, '%Y-%m-%d %H:%M')
|
|
60
|
+
except ValueError:
|
|
61
|
+
try:
|
|
62
|
+
return datetime.strptime(datetime_str, '%H:%M').replace(
|
|
63
|
+
year=datetime.now().year,
|
|
64
|
+
month=datetime.now().month,
|
|
65
|
+
day=datetime.now().day
|
|
66
|
+
)
|
|
67
|
+
except ValueError:
|
|
68
|
+
raise ValueError("Invalid datetime format. Use 'YYYY-MM-DD HH:MM' or 'HH:MM'")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def parse_date(date_str):
|
|
72
|
+
"""Parse date string in format YYYY-MM-DD."""
|
|
73
|
+
try:
|
|
74
|
+
return datetime.strptime(date_str, '%Y-%m-%d').date()
|
|
75
|
+
except ValueError:
|
|
76
|
+
raise ValueError("Invalid date format. Use 'YYYY-MM-DD'")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def random_mouse_movement():
|
|
80
|
+
"""Move the mouse by a small random offset."""
|
|
81
|
+
dx = random.randint(-30, 30)
|
|
82
|
+
dy = random.randint(-30, 30)
|
|
83
|
+
mouse.move(dx, dy)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def random_keyboard_action():
|
|
87
|
+
"""Press a random navigation key."""
|
|
88
|
+
actions = [Key.page_up, Key.page_down, Key.up, Key.down, Key.left, Key.right]
|
|
89
|
+
if random.random() < 0.8:
|
|
90
|
+
key = random.choice(actions)
|
|
91
|
+
keyboard.press(key)
|
|
92
|
+
time.sleep(random.uniform(0.02, 0.08))
|
|
93
|
+
keyboard.release(key)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _run_activity_loop(stop_time):
|
|
97
|
+
"""Core activity loop — runs until stop_time."""
|
|
98
|
+
actions_per_second = (50 + 60) / 60 # ~1.83 actions per second
|
|
99
|
+
|
|
100
|
+
while datetime.now() < stop_time:
|
|
101
|
+
start_time = time.time()
|
|
102
|
+
|
|
103
|
+
# Perform a burst of actions
|
|
104
|
+
actions_this_cycle = random.randint(3, 8)
|
|
105
|
+
|
|
106
|
+
for _ in range(actions_this_cycle):
|
|
107
|
+
if random.random() < 0.55: # Slightly favor mouse movements
|
|
108
|
+
random_mouse_movement()
|
|
109
|
+
else:
|
|
110
|
+
random_keyboard_action()
|
|
111
|
+
|
|
112
|
+
time.sleep(random.uniform(0.02, 0.1))
|
|
113
|
+
|
|
114
|
+
# Maintain target rate
|
|
115
|
+
elapsed = time.time() - start_time
|
|
116
|
+
target_time = actions_this_cycle / actions_per_second
|
|
117
|
+
|
|
118
|
+
if elapsed < target_time:
|
|
119
|
+
time.sleep(target_time - elapsed)
|
|
120
|
+
|
|
121
|
+
# Occasionally add a brief pause (10% chance)
|
|
122
|
+
if random.random() < 0.1:
|
|
123
|
+
idle_time = random.uniform(0.5, 2.0)
|
|
124
|
+
print(f"Brief pause for {idle_time:.2f} seconds...")
|
|
125
|
+
time.sleep(idle_time)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def perform_actions(stop_time, close_anydesk_on_exit, sleep_on_exit, end_date=None, start_time_str=None):
|
|
129
|
+
"""
|
|
130
|
+
Run simulated activity until stop_time, then optionally close AnyDesk and sleep.
|
|
131
|
+
|
|
132
|
+
If end_date is provided, the script runs daily:
|
|
133
|
+
- Each day it runs from start_time_str (or now) until the --until time.
|
|
134
|
+
- After each day's session, it sleeps until the next day's start time.
|
|
135
|
+
- On the final day (end_date), it runs the last session and then exits.
|
|
136
|
+
"""
|
|
137
|
+
print(f"Detected OS: {CURRENT_OS}")
|
|
138
|
+
print(f"Modifier key: {'Cmd' if CURRENT_OS == 'darwin' else 'Ctrl'}")
|
|
139
|
+
print(f"On exit: close AnyDesk={'yes' if close_anydesk_on_exit else 'no'}, "
|
|
140
|
+
f"sleep={'yes' if sleep_on_exit else 'no'}")
|
|
141
|
+
|
|
142
|
+
if end_date:
|
|
143
|
+
daily_stop_hour = stop_time.hour
|
|
144
|
+
daily_stop_minute = stop_time.minute
|
|
145
|
+
daily_start_hour = int(start_time_str.split(':')[0]) if start_time_str else datetime.now().hour
|
|
146
|
+
daily_start_minute = int(start_time_str.split(':')[1]) if start_time_str else datetime.now().minute
|
|
147
|
+
|
|
148
|
+
print(f"Multi-day mode: running daily {daily_start_hour:02d}:{daily_start_minute:02d} → "
|
|
149
|
+
f"{daily_stop_hour:02d}:{daily_stop_minute:02d} until {end_date}")
|
|
150
|
+
print("-" * 50)
|
|
151
|
+
|
|
152
|
+
current_date = date.today()
|
|
153
|
+
|
|
154
|
+
while current_date <= end_date:
|
|
155
|
+
today_start = datetime(current_date.year, current_date.month, current_date.day,
|
|
156
|
+
daily_start_hour, daily_start_minute)
|
|
157
|
+
today_stop = datetime(current_date.year, current_date.month, current_date.day,
|
|
158
|
+
daily_stop_hour, daily_stop_minute)
|
|
159
|
+
|
|
160
|
+
now = datetime.now()
|
|
161
|
+
|
|
162
|
+
# If we haven't reached start time yet today, wait
|
|
163
|
+
if now < today_start:
|
|
164
|
+
wait_seconds = (today_start - now).total_seconds()
|
|
165
|
+
print(f"[{current_date}] Waiting {wait_seconds/60:.0f} min until start time "
|
|
166
|
+
f"{daily_start_hour:02d}:{daily_start_minute:02d}...")
|
|
167
|
+
time.sleep(wait_seconds)
|
|
168
|
+
|
|
169
|
+
# If we've already passed today's stop time, skip to next day
|
|
170
|
+
if datetime.now() >= today_stop:
|
|
171
|
+
print(f"[{current_date}] Already past stop time, skipping to next day.")
|
|
172
|
+
current_date += timedelta(days=1)
|
|
173
|
+
continue
|
|
174
|
+
|
|
175
|
+
print(f"[{current_date}] Running until {today_stop.strftime('%H:%M')}...")
|
|
176
|
+
_run_activity_loop(today_stop)
|
|
177
|
+
print(f"[{current_date}] Day session complete.")
|
|
178
|
+
|
|
179
|
+
current_date += timedelta(days=1)
|
|
180
|
+
|
|
181
|
+
# If there are more days, sleep overnight (idle wait)
|
|
182
|
+
if current_date <= end_date:
|
|
183
|
+
next_start = datetime(current_date.year, current_date.month, current_date.day,
|
|
184
|
+
daily_start_hour, daily_start_minute)
|
|
185
|
+
wait_seconds = (next_start - datetime.now()).total_seconds()
|
|
186
|
+
if wait_seconds > 0:
|
|
187
|
+
print(f"Sleeping until next session: {next_start.strftime('%Y-%m-%d %H:%M')} "
|
|
188
|
+
f"({wait_seconds/3600:.1f} hours)")
|
|
189
|
+
time.sleep(wait_seconds)
|
|
190
|
+
|
|
191
|
+
print("End date reached. All sessions complete.")
|
|
192
|
+
else:
|
|
193
|
+
# Single-run mode (original behavior)
|
|
194
|
+
print(f"Running until {stop_time.strftime('%Y-%m-%d %H:%M')}...")
|
|
195
|
+
print("-" * 50)
|
|
196
|
+
_run_activity_loop(stop_time)
|
|
197
|
+
print("Stop time reached. Exiting script.")
|
|
198
|
+
|
|
199
|
+
if close_anydesk_on_exit:
|
|
200
|
+
close_anydesk()
|
|
201
|
+
|
|
202
|
+
if sleep_on_exit:
|
|
203
|
+
put_to_sleep()
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: desk-awake
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Cross-platform idle activity simulator with AnyDesk integration
|
|
5
|
+
Author: Abhinav Hudda
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: pynput>=1.7.0
|
|
10
|
+
Provides-Extra: mac
|
|
11
|
+
Requires-Dist: pyobjc-core>=9.0; extra == "mac"
|
|
12
|
+
Requires-Dist: pyobjc-framework-ApplicationServices>=9.0; extra == "mac"
|
|
13
|
+
Requires-Dist: pyobjc-framework-Cocoa>=9.0; extra == "mac"
|
|
14
|
+
Requires-Dist: pyobjc-framework-Quartz>=9.0; extra == "mac"
|
|
15
|
+
|
|
16
|
+
# Desk Awake
|
|
17
|
+
|
|
18
|
+
Cross-platform idle activity simulator. Keeps your session active by generating mouse movements and keyboard actions until a specified time.
|
|
19
|
+
|
|
20
|
+
Auto-detects the OS and uses appropriate modifier keys (`Cmd` on macOS, `Ctrl` on Linux/Windows) and system commands.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install desk-awake
|
|
26
|
+
|
|
27
|
+
# On macOS, include the optional mac dependencies
|
|
28
|
+
pip install "desk-awake[mac]"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
Once installed, the `desk-awake` command is available globally:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Run until a specific time (24h format)
|
|
37
|
+
desk-awake --until "18:30"
|
|
38
|
+
|
|
39
|
+
# Run until a specific date and time
|
|
40
|
+
desk-awake --until "2025-01-15 17:00"
|
|
41
|
+
|
|
42
|
+
# Short flag works too
|
|
43
|
+
desk-awake -u "18:30"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Multi-day mode
|
|
47
|
+
|
|
48
|
+
Run daily on a schedule until a specific end date:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Run every day from 09:00 to 18:30, until June 15th
|
|
52
|
+
desk-awake -u "18:30" --start "09:00" --end-date "2026-06-15"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Exit behavior flags
|
|
56
|
+
|
|
57
|
+
| Flag | Description |
|
|
58
|
+
|------|-------------|
|
|
59
|
+
| `--close-anydesk` | Close AnyDesk when done (default) |
|
|
60
|
+
| `--no-close-anydesk` | Don't close AnyDesk when done |
|
|
61
|
+
| `--sleep` | Put machine to sleep when done |
|
|
62
|
+
| `--no-sleep` | Don't sleep when done |
|
|
63
|
+
|
|
64
|
+
### OS-specific defaults
|
|
65
|
+
|
|
66
|
+
| OS | Close AnyDesk | Sleep |
|
|
67
|
+
|----|---------------|-------|
|
|
68
|
+
| macOS | ✅ | ✅ |
|
|
69
|
+
| Linux | ✅ | ❌ |
|
|
70
|
+
| Windows | ✅ | ✅ |
|
|
71
|
+
|
|
72
|
+
Override any default with the flags above.
|
|
73
|
+
|
|
74
|
+
### Examples
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Ubuntu: run until 6:30 PM, close AnyDesk, no sleep (default)
|
|
78
|
+
desk-awake -u "18:30"
|
|
79
|
+
|
|
80
|
+
# macOS: run until 6:30 PM, close AnyDesk, sleep (default)
|
|
81
|
+
desk-awake -u "18:30"
|
|
82
|
+
|
|
83
|
+
# macOS: skip sleep
|
|
84
|
+
desk-awake -u "18:30" --no-sleep
|
|
85
|
+
|
|
86
|
+
# Linux: force sleep too
|
|
87
|
+
desk-awake -u "18:30" --sleep
|
|
88
|
+
|
|
89
|
+
# Multi-day: run 09:00–18:30 daily until a date
|
|
90
|
+
desk-awake -u "18:30" -s "09:00" -e "2026-06-15"
|
|
91
|
+
|
|
92
|
+
# Keep everything running, don't close anything
|
|
93
|
+
desk-awake -u "18:30" --no-close-anydesk --no-sleep
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Running without installing
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
python -m desk_awake --until "18:30"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Requirements
|
|
103
|
+
|
|
104
|
+
- Python 3.8+
|
|
105
|
+
- `pynput` (installed automatically)
|
|
106
|
+
- On macOS: `pyobjc` packages (install with `pip install "desk-awake[mac]"`)
|
|
107
|
+
- On Linux: may need `xdotool` or X11 libs depending on your display server
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/desk_awake/__init__.py
|
|
4
|
+
src/desk_awake/__main__.py
|
|
5
|
+
src/desk_awake/cli.py
|
|
6
|
+
src/desk_awake/core.py
|
|
7
|
+
src/desk_awake.egg-info/PKG-INFO
|
|
8
|
+
src/desk_awake.egg-info/SOURCES.txt
|
|
9
|
+
src/desk_awake.egg-info/dependency_links.txt
|
|
10
|
+
src/desk_awake.egg-info/entry_points.txt
|
|
11
|
+
src/desk_awake.egg-info/requires.txt
|
|
12
|
+
src/desk_awake.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
desk_awake
|