udemyBot / app.py
imseldrith's picture
Update app.py
2a6e962 verified
raw
history blame
5.45 kB
from flask import Flask, render_template_string, jsonify
from apscheduler.schedulers.background import BackgroundScheduler
import subprocess
import threading
import pytz
import logging
from datetime import datetime
# Initialize Flask app
app = Flask(__name__)
# Setup logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
# Execution logs
execution_logs = []
MAX_LOG_ENTRIES = 50
log_lock = threading.Lock() # Prevents race conditions when modifying logs
def add_log_entry(entry):
"""Safely add log entries while maintaining MAX_LOG_ENTRIES limit."""
with log_lock:
execution_logs.append(entry)
if len(execution_logs) > MAX_LOG_ENTRIES:
execution_logs.pop(0)
def get_ist_time():
"""Get the current time in IST (Indian Standard Time)."""
utc_now = datetime.utcnow()
ist_timezone = pytz.timezone("Asia/Kolkata")
return utc_now.replace(tzinfo=pytz.utc).astimezone(ist_timezone)
def run_cli_script():
"""Runs cli.py and streams logs in real-time to both UI and terminal."""
timestamp = get_ist_time().strftime("%Y-%m-%d %H:%M:%S IST")
try:
process = subprocess.Popen(
["python", "cli.py"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
stdout, stderr = process.communicate() # Wait for process to complete
if stdout:
add_log_entry({'time': timestamp, 'output': stdout, 'error': ''})
logging.info(stdout.strip())
if stderr:
add_log_entry({'time': timestamp, 'output': '', 'error': stderr})
logging.error(stderr.strip())
except Exception as e:
error_msg = str(e)
add_log_entry({'time': timestamp, 'output': '', 'error': error_msg})
logging.error(f"Error: {error_msg}")
def start_initial_run():
"""Runs the CLI script immediately upon startup in a separate thread."""
threading.Thread(target=run_cli_script, daemon=True).start()
# Initialize scheduler
scheduler = BackgroundScheduler(daemon=True)
scheduler.add_job(
run_cli_script,
'interval',
hours=3,
id='main_job',
next_run_time=datetime.now()
)
scheduler.start()
# Ensure script runs once on startup
start_initial_run()
@app.route('/')
def home():
"""Main UI displaying logs and next run time."""
job = scheduler.get_job('main_job')
next_run = get_ist_time().strftime('%Y-%m-%d %H:%M:%S IST') if job else 'N/A'
return render_template_string('''
<!DOCTYPE html>
<html>
<head>
<title>Script Scheduler</title>
<script>
function fetchLogs() {
fetch('/logs')
.then(response => response.json())
.then(data => {
let logBox = document.getElementById("log-box");
logBox.innerHTML = "";
data.logs.forEach(log => {
let logEntry = "<div class='timestamp'>" + log.time + "</div>";
if (log.output) logEntry += "<div class='output'>" + log.output + "</div>";
if (log.error) logEntry += "<div class='error'>" + log.error + "</div>";
logEntry += "<hr>";
logBox.innerHTML += logEntry;
});
logBox.scrollTop = logBox.scrollHeight;
});
}
setInterval(fetchLogs, 2000);
window.onload = fetchLogs;
</script>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.log-box {
background: #000;
color: #0f0;
padding: 15px;
border-radius: 5px;
margin-top: 20px;
white-space: pre-wrap;
max-height: 400px;
overflow-y: auto;
}
.timestamp { color: #888; margin-bottom: 10px; }
.error { color: #ff4444; }
</style>
</head>
<body>
<h1>Script Scheduler</h1>
<p>Next run: {{ next_run }}</p>
<h2>Latest Execution Logs</h2>
<div id="log-box" class="log-box"></div>
<p><a href="/force-run">Trigger Manual Run</a></p>
<p><a href="/run-check">Check Scheduler Status</a></p>
</body>
</html>
''', next_run=next_run)
@app.route('/logs')
def logs():
"""Returns logs as JSON for AJAX polling."""
return jsonify({'logs': execution_logs})
@app.route('/force-run')
def force_run():
"""Manually trigger the script execution."""
threading.Thread(target=run_cli_script, daemon=True).start()
logging.info("Manual script execution triggered")
return "Script executed manually", 200
@app.route('/run-check')
def run_check():
"""Check if the scheduler is still running and restart if necessary."""
if not scheduler.running:
logging.warning("Scheduler was stopped! Restarting...")
scheduler.start()
return "Scheduler restarted", 200
return "Scheduler is running", 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)