homepage/main.py

184 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from flask import Flask, render_template, request, jsonify, make_response
import yaml
from datetime import datetime
import os
import requests
import time
import locale
import socket
from threading import Thread
app = Flask(__name__)
CONFIG_PATH = 'config.yaml'
# Кэш для погоды
weather_cache = {'data': None, 'ts': 0}
# Кэш для прогноза
weather_forecast_cache = {'data': None, 'ts': 0}
def load_config():
with open(CONFIG_PATH, encoding='utf-8') as f:
return yaml.safe_load(f)
def save_config(yaml_text):
with open(CONFIG_PATH, 'w', encoding='utf-8') as f:
f.write(yaml_text)
def get_weather_cache_ttl():
config = load_config()
w = config.get('weather', {})
ttl = w.get('cache_ttl')
try:
return int(ttl) * 60 if ttl else 3600
except Exception:
return 3600
def get_weather():
global weather_cache
now = time.time()
WEATHER_CACHE_TTL = get_weather_cache_ttl()
if weather_cache['data'] and now - weather_cache['ts'] < WEATHER_CACHE_TTL:
return weather_cache['data']
config = load_config()
w = config.get('weather', {})
api_key = w.get('api_key')
lat = w.get('lat')
lon = w.get('lon')
if not api_key or not lat or not lon:
return None
url = f"https://api.weatherapi.com/v1/current.json?key={api_key}&q={lat},{lon}&lang=ru"
try:
resp = requests.get(url, timeout=5)
resp.raise_for_status()
data = resp.json()
temp = data['current']['temp_c']
cloud = data['current']['cloud']
condition = data['current'].get('condition', {})
icon = condition.get('icon', '')
text = condition.get('text', '')
result = {'temp': temp, 'cloud': cloud, 'icon': icon, 'text': text}
weather_cache = {'data': result, 'ts': now}
return result
except Exception:
return None
def get_weather_forecast():
global weather_forecast_cache
now = time.time()
WEATHER_CACHE_TTL = get_weather_cache_ttl()
if weather_forecast_cache['data'] and now - weather_forecast_cache['ts'] < WEATHER_CACHE_TTL:
return weather_forecast_cache['data']
config = load_config()
w = config.get('weather', {})
api_key = w.get('api_key')
lat = w.get('lat')
lon = w.get('lon')
if not api_key or not lat or not lon:
raise Exception('Не заданы api_key, lat или lon')
url = f"https://api.weatherapi.com/v1/forecast.json?key={api_key}&q={lat},{lon}&days=10&lang=ru"
try:
resp = requests.get(url, timeout=5)
resp.raise_for_status()
data = resp.json()
forecast = []
for day in data['forecast']['forecastday']:
d = day['day']
temp = d.get('avgtemp_c')
if temp is None:
temp = d.get('maxtemp_c')
cloud = d.get('cloud', 0)
condition = d.get('condition', {})
forecast.append({
'date': day['date'],
'temp': temp,
'cloud': cloud,
'text': condition.get('text', ''),
'icon': condition.get('icon', '')
})
weather_forecast_cache = {'data': forecast, 'ts': now}
return forecast
except Exception as e:
try:
return {'_error': resp.text}
except:
return {'_error': str(e)}
def check_services_status(services, timeout=2):
"""
Проверяет доступность всех сервисов из списка.
Возвращает True, если все доступны, иначе False.
"""
import requests
for srv in services:
url = srv.get('url')
name = srv.get('name', url)
try:
resp = requests.get(url, timeout=timeout, verify=False)
if not (200 <= resp.status_code < 400):
return False, name
except Exception:
return False, name
return True, None
@app.route('/api/config', methods=['GET'])
def get_config():
try:
with open(CONFIG_PATH, encoding='utf-8') as f:
content = f.read()
return jsonify({'content': content})
except Exception as e:
return make_response(jsonify({'error': str(e)}), 500)
@app.route('/api/config', methods=['POST'])
def update_config():
data = request.get_json()
yaml_text = data.get('content', '')
try:
# Проверка валидности yaml
yaml.safe_load(yaml_text)
save_config(yaml_text)
return jsonify({'status': 'ok'})
except Exception as e:
return make_response(jsonify({'error': str(e)}), 400)
@app.route('/api/weather-forecast', methods=['GET'])
def api_weather_forecast():
forecast = get_weather_forecast()
if forecast is None:
return {'error': 'Ошибка получения прогноза'}, 500
if isinstance(forecast, dict) and '_error' in forecast:
return {'error': forecast['_error']}, 500
return {'forecast': forecast}
@app.route('/api/services-status', methods=['GET'])
def api_services_status():
config = load_config()
check_online = config.get('checkOnline', [])
status, failed_name = check_services_status(check_online) if check_online else (None, None)
return jsonify({'all_services_up': status, 'failed_service': failed_name})
# config = load_config() # Удаляем глобальную переменную
@app.route('/')
def index():
# Словари для русских дат
days = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье']
months = [
'', 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня',
'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'
]
now = datetime.now()
day = days[now.weekday()]
month = months[now.month]
now_str = f"{day}, {now.day} {month} {now.year}"
current_time = now.strftime('%H:%M:%S')
weather = get_weather()
config = load_config() # Загружаем актуальный конфиг при каждом запросе
return render_template('index.html', applications=config['applications'], bookmarks=config['bookmarks'], now=now_str, current_time=current_time, weather=weather)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')