Files
Modus/modules/launcher/plugins/caffeine.py
T

156 lines
5.3 KiB
Python

"""
Caffeine plugin for the launcher.
Prevents system from going idle for a specified duration.
"""
import subprocess
from typing import List
import gi
import utils.icons as icons
from fabric.utils import get_relative_path
from modules.launcher.plugin_base import PluginBase
from modules.launcher.result import Result
gi.require_version("Gtk", "3.0")
class CaffeinePlugin(PluginBase):
"""
Plugin for preventing system idle using the inhibit script.
"""
def __init__(self):
super().__init__()
self.display_name = "Caffeine"
self.description = "Prevent system from going idle"
self.inhibit_script = get_relative_path("../../../utils/inhibit.py")
# Predefined durations
self.durations = {
"30m": "30 minutes",
"1h": "1 hour",
"2h": "2 hours",
"4h": "4 hours",
"8h": "8 hours",
"on": "On",
"off": "Off",
}
def initialize(self):
"""Initialize the caffeine plugin."""
self.set_triggers(["caffeine", "caffeine "])
def cleanup(self):
"""Cleanup the caffeine plugin."""
pass
def _create_inhibit_action(self, duration: str):
"""Create an inhibit action that properly captures the duration."""
def action():
try:
# Run the script in the background without waiting
subprocess.Popen(
["python3", self.inhibit_script, duration],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True, # Run in a new session to prevent hanging
)
except Exception as e:
print(f"Error starting inhibit script: {e}")
return action
def _is_valid_duration(self, query: str) -> bool:
"""Check if the query is a valid duration format."""
if query in self.durations:
return True
if query.isdigit():
return True
if query.endswith(("h", "m", "s")) and query[:-1].replace(".", "").isdigit():
return True
return False
def _get_default_action(self, query: str):
"""Get the default action for a direct duration input."""
if self._is_valid_duration(query):
return self._create_inhibit_action(query)
return None
def query(self, query_string: str) -> List[Result]:
"""Search caffeine durations based on query."""
# For empty queries, show all available durations
if not query_string.strip():
query_string = "" # Will match all durations in the loop below
query = query_string.lower().strip()
results = []
# Handle direct search entry (e.g., "caffeine 30m" or just "30m")
if query.startswith("caffeine "):
query = query[9:].strip() # Remove "caffeine " prefix
# If query becomes empty after removing prefix, show all durations
if not query:
query = "" # Will match all durations in the loop below
elif query == "caffeine":
# Handle just "caffeine" without space - show all durations
query = ""
elif not query:
# Handle empty query - show all durations
pass
elif (
query in self.durations
or query.isdigit()
or (
query.endswith(("h", "m", "s"))
and query[:-1].replace(".", "").isdigit()
)
):
# If query is a valid duration without prefix, use it directly
pass
else:
return []
# Add custom duration option
if query.isdigit() or (
query.endswith(("h", "m", "s")) and query[:-1].replace(".", "").isdigit()
):
result = Result(
title=f"Custom: {query}",
subtitle="Set custom duration",
icon_markup=icons.coffee,
action=self._create_inhibit_action(query),
relevance=1.0,
plugin_name=self.display_name,
data={"duration": query},
)
results.append(result)
# Add predefined durations
for duration, description in self.durations.items():
# If query is empty, show all durations; otherwise filter by query
if not query or query in duration or query in description.lower():
# Special handling for "off" - it should stop inhibition
if duration.lower() == "off":
subtitle = "Stop idle inhibition"
else:
subtitle = f"Prevent idle for {description.lower()}"
result = Result(
title=description,
subtitle=subtitle,
icon_markup=icons.coffee,
action=self._create_inhibit_action(duration),
relevance=0.9 if query == duration else 0.7,
plugin_name=self.display_name,
data={"duration": duration},
)
results.append(result)
# Set default action for direct duration input
if results:
results[0].default_action = self._get_default_action(query)
return results