add start stop

This commit is contained in:
Aron Petau 2026-01-02 13:41:21 +01:00
parent c68ee12d4e
commit 29a3f629e2
4 changed files with 69 additions and 3 deletions

View file

@ -1,8 +1,27 @@
Autopilot bot command list for @BotFather Autopilot bot command list for @BotFather
=== BOT DESCRIPTION (for @BotFather /setdescription) ===
🏠 Monitors 6 Berlin housing companies (HOWOGE, Gewobag, Degewo, Gesobau, Stadt und Land, WBM) + WG-Company for new apartments.
✅ Instant Telegram notifications
🤖 Autopilot: auto-fill & submit applications
📊 Weekly listing patterns & error tracking
🔄 Retry failed applications with one command
⏸️ Pause/resume monitoring anytime
Perfect for Berlin apartment hunters who want to apply first!
=== BOT ABOUT (for @BotFather /setabouttext) ===
Automated Berlin apartment monitoring bot with auto-apply functionality for inberlinwohnen.de and wgcompany.de listings.
=== COMMANDS (for @BotFather /setcommands) ===
Use @BotFather -> setcommands and paste the following lines exactly (one per line): Use @BotFather -> setcommands and paste the following lines exactly (one per line):
start - Resume monitoring for new listings
stop - Pause monitoring (bot stays running, commands still work)
autopilot - Enable or disable automatic applications. Usage: autopilot on or autopilot off autopilot - Enable or disable automatic applications. Usage: autopilot on or autopilot off
status - Show current status and statistics (autopilot state, application counts by company) status - Show current status and statistics (autopilot state, application counts by company)
plot - Show weekly listing patterns (image) plot - Show weekly listing patterns (image)

View file

@ -139,6 +139,13 @@ async def main() -> None:
last_clean = now last_clean = now
try: try:
# Check if monitoring is enabled before fetching listings
if not state_manager.is_monitoring_enabled():
logger.debug("Monitoring is paused, skipping listing check")
await asyncio.sleep(CHECK_INTERVAL)
_flush_rotating_file_handlers()
continue
current_listings = await app_handler.fetch_listings() current_listings = await app_handler.fetch_listings()
except Exception as e: except Exception as e:
logger.error(f"💥 Browser crash: {e}") logger.error(f"💥 Browser crash: {e}")

View file

@ -25,7 +25,7 @@ class StateManager:
if self.state_file.exists(): if self.state_file.exists():
with open(self.state_file, "r") as f: with open(self.state_file, "r") as f:
return json.load(f) return json.load(f)
return {"autopilot": False} return {"autopilot": False, "monitoring_enabled": True}
def save_state(self, state: dict) -> None: def save_state(self, state: dict) -> None:
"""Save persistent state""" """Save persistent state"""
@ -43,6 +43,17 @@ class StateManager:
"""Check if autopilot mode is enabled""" """Check if autopilot mode is enabled"""
return self.load_state().get("autopilot", False) return self.load_state().get("autopilot", False)
def set_monitoring_enabled(self, enabled: bool) -> None:
"""Enable or disable monitoring"""
state = self.load_state()
state["monitoring_enabled"] = enabled
self.save_state(state)
logger.info(f"Monitoring {'enabled' if enabled else 'disabled'}")
def is_monitoring_enabled(self) -> bool:
"""Check if monitoring is enabled"""
return self.load_state().get("monitoring_enabled", True)
def set_logged_in(self, status: bool) -> None: def set_logged_in(self, status: bool) -> None:
"""Set the logged_in status""" """Set the logged_in status"""
self.logged_in = status self.logged_in = status

View file

@ -20,6 +20,8 @@ class TelegramBot:
"""Send a help message with available commands.""" """Send a help message with available commands."""
help_text = ( help_text = (
"<b>Available commands:</b>\n" "<b>Available commands:</b>\n"
"/start - Resume monitoring\n"
"/stop - Pause monitoring\n"
"/autopilot on|off - Enable/disable autopilot\n" "/autopilot on|off - Enable/disable autopilot\n"
"/status - Show current status\n" "/status - Show current status\n"
"/plot - Show weekly listing pattern plot\n" "/plot - Show weekly listing pattern plot\n"
@ -38,6 +40,25 @@ class TelegramBot:
) )
await self._send_message(msg) await self._send_message(msg)
async def _handle_start_command(self) -> None:
"""Resume monitoring for new listings."""
self.monitor.state_manager.set_monitoring_enabled(True)
await self._send_message(
"▶️ <b>Monitoring RESUMED</b>\n\n"
"Bot will now check for new listings and notify you."
)
logger.info("Monitoring resumed via /start command")
async def _handle_stop_command(self) -> None:
"""Pause monitoring without stopping the bot."""
self.monitor.state_manager.set_monitoring_enabled(False)
await self._send_message(
"⏸️ <b>Monitoring PAUSED</b>\n\n"
"Bot will not check for new listings until you send /start.\n"
"Commands like /status, /plot, and /retryfailed still work."
)
logger.info("Monitoring paused via /stop command")
async def _handle_reset_listings_command(self) -> None: async def _handle_reset_listings_command(self) -> None:
"""Move listings.json to data/old/ with a timestamp, preserving statistics and application history.""" """Move listings.json to data/old/ with a timestamp, preserving statistics and application history."""
import shutil import shutil
@ -133,7 +154,11 @@ class TelegramBot:
return return
logger.info(f"Received Telegram command: {text}") logger.info(f"Received Telegram command: {text}")
loop = self.event_loop loop = self.event_loop
if text.startswith("/autopilot"): if text == "/start":
asyncio.run_coroutine_threadsafe(self._handle_start_command(), loop)
elif text == "/stop":
asyncio.run_coroutine_threadsafe(self._handle_stop_command(), loop)
elif text.startswith("/autopilot"):
asyncio.run_coroutine_threadsafe(self._handle_autopilot_command(text), loop) asyncio.run_coroutine_threadsafe(self._handle_autopilot_command(text), loop)
elif text == "/status": elif text == "/status":
asyncio.run_coroutine_threadsafe(self._handle_status_command(), loop) asyncio.run_coroutine_threadsafe(self._handle_status_command(), loop)
@ -230,9 +255,13 @@ class TelegramBot:
async def _handle_status_command(self) -> None: async def _handle_status_command(self) -> None:
state = self.app_handler.load_state() state = self.app_handler.load_state()
autopilot = state.get("autopilot", False) autopilot = state.get("autopilot", False)
monitoring = state.get("monitoring_enabled", True)
applications = self.app_handler.load_applications() applications = self.app_handler.load_applications()
status = "<b>Autopilot:</b> " + ("ON" if autopilot else "OFF")
status = "<b>Monitoring:</b> " + ("▶️ RUNNING" if monitoring else "⏸️ PAUSED")
status += "\n<b>Autopilot:</b> " + ("✅ ON" if autopilot else "🛑 OFF")
status += f"\n📝 <b>Applications sent:</b> {len(applications)}" status += f"\n📝 <b>Applications sent:</b> {len(applications)}"
by_company: dict[str, int] = {} by_company: dict[str, int] = {}
for app in applications.values(): for app in applications.values():
company = app.get("company", "unknown") company = app.get("company", "unknown")