mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-22 10:51:02 +01:00
chore: add watchdog support for backend HMR
This commit is contained in:
@@ -1,10 +1,6 @@
|
||||
FROM python:3.9
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["python", "run.py"]
|
||||
CMD ["python", "run_dev.py"]
|
||||
@@ -16,6 +16,7 @@ os.makedirs(FORMAT_DIR, exist_ok=True)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@bp.route('', methods=['GET', 'POST'])
|
||||
def handle_formats():
|
||||
if request.method == 'POST':
|
||||
@@ -26,6 +27,7 @@ def handle_formats():
|
||||
formats = load_all_formats()
|
||||
return jsonify(formats)
|
||||
|
||||
|
||||
@bp.route('/<int:id>', methods=['GET', 'PUT', 'DELETE'])
|
||||
def handle_format(id):
|
||||
if request.method == 'GET':
|
||||
@@ -46,14 +48,17 @@ def handle_format(id):
|
||||
return jsonify(result), 400
|
||||
return jsonify(result), 200
|
||||
|
||||
|
||||
def is_format_used_in_profile(format_id):
|
||||
profiles = load_all_profiles()
|
||||
for profile in profiles:
|
||||
for custom_format in profile.get('custom_formats', []):
|
||||
if custom_format.get('id') == format_id and custom_format.get('score', 0) != 0:
|
||||
if custom_format.get('id') == format_id and custom_format.get(
|
||||
'score', 0) != 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def save_format(data):
|
||||
logger.info("Received data for saving format: %s", data)
|
||||
|
||||
@@ -71,9 +76,11 @@ def save_format(data):
|
||||
existing_filename = os.path.join(FORMAT_DIR, f"{format_id}.yml")
|
||||
if os.path.exists(existing_filename):
|
||||
existing_data = load_format(format_id)
|
||||
date_created = existing_data.get('date_created', get_current_timestamp())
|
||||
date_created = existing_data.get('date_created',
|
||||
get_current_timestamp())
|
||||
else:
|
||||
raise FileNotFoundError(f"No existing file found for ID: {format_id}")
|
||||
raise FileNotFoundError(
|
||||
f"No existing file found for ID: {format_id}")
|
||||
|
||||
date_modified = get_current_timestamp()
|
||||
|
||||
@@ -81,12 +88,11 @@ def save_format(data):
|
||||
conditions = []
|
||||
for condition in data.get('conditions', []):
|
||||
logger.info("Processing condition: %s", condition)
|
||||
cond_dict = OrderedDict([
|
||||
('type', condition['type']),
|
||||
('name', sanitize_input(condition['name'])),
|
||||
('negate', condition.get('negate', False)),
|
||||
('required', condition.get('required', False))
|
||||
])
|
||||
cond_dict = OrderedDict([('type', condition['type']),
|
||||
('name', sanitize_input(condition['name'])),
|
||||
('negate', condition.get('negate', False)),
|
||||
('required', condition.get('required',
|
||||
False))])
|
||||
if condition['type'] == 'regex':
|
||||
cond_dict['regex_id'] = condition['regex_id']
|
||||
elif condition['type'] == 'size':
|
||||
@@ -100,25 +106,25 @@ def save_format(data):
|
||||
tags = [sanitize_input(tag) for tag in data.get('tags', [])]
|
||||
|
||||
# Construct the ordered data
|
||||
ordered_data = OrderedDict([
|
||||
('id', format_id),
|
||||
('name', name),
|
||||
('description', description),
|
||||
('date_created', str(date_created)),
|
||||
('date_modified', str(date_modified)),
|
||||
('conditions', conditions),
|
||||
('tags', tags)
|
||||
])
|
||||
ordered_data = OrderedDict([('id', format_id), ('name', name),
|
||||
('description', description),
|
||||
('date_created', str(date_created)),
|
||||
('date_modified', str(date_modified)),
|
||||
('conditions', conditions), ('tags', tags)])
|
||||
|
||||
# Generate the filename using only the ID
|
||||
filename = os.path.join(FORMAT_DIR, f"{format_id}.yml")
|
||||
|
||||
|
||||
# Write to the file
|
||||
with open(filename, 'w') as file:
|
||||
yaml.dump(ordered_data, file, default_flow_style=False, Dumper=yaml.SafeDumper)
|
||||
|
||||
yaml.dump(ordered_data,
|
||||
file,
|
||||
default_flow_style=False,
|
||||
Dumper=yaml.SafeDumper)
|
||||
|
||||
return ordered_data
|
||||
|
||||
|
||||
def load_format(id):
|
||||
filename = os.path.join(FORMAT_DIR, f"{id}.yml")
|
||||
if os.path.exists(filename):
|
||||
@@ -127,12 +133,16 @@ def load_format(id):
|
||||
return data
|
||||
return None
|
||||
|
||||
|
||||
def delete_format(id):
|
||||
if is_format_used_in_profile(id):
|
||||
return {"error": "Format in use", "message": "This format is being used in one or more profiles."}
|
||||
|
||||
return {
|
||||
"error": "Format in use",
|
||||
"message": "This format is being used in one or more profiles."
|
||||
}
|
||||
|
||||
filename = os.path.join(FORMAT_DIR, f"{id}.yml")
|
||||
if os.path.exists(filename):
|
||||
os.remove(filename)
|
||||
return {"message": f"Format with ID {id} deleted."}
|
||||
return {"error": f"Format with ID {id} not found."}
|
||||
return {"error": f"Format with ID {id} not found."}
|
||||
|
||||
@@ -3,4 +3,5 @@ Flask-CORS==3.0.10
|
||||
PyYAML==5.4.1
|
||||
requests==2.26.0
|
||||
Werkzeug==2.0.1
|
||||
GitPython==3.1.24
|
||||
GitPython==3.1.24
|
||||
watchdog
|
||||
@@ -2,4 +2,4 @@ from app import create_app
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = create_app()
|
||||
app.run(debug=True, host='0.0.0.0')
|
||||
app.run(debug=True, host='0.0.0.0')
|
||||
|
||||
49
backend/run_dev.py
Normal file
49
backend/run_dev.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import sys
|
||||
import time
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import FileSystemEventHandler
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
|
||||
class Reloader(FileSystemEventHandler):
|
||||
|
||||
def __init__(self):
|
||||
self.process = None
|
||||
self.last_restart = 0
|
||||
self.start_app()
|
||||
|
||||
def on_any_event(self, event):
|
||||
if event.src_path.endswith(
|
||||
'.py') and not event.src_path.endswith('run_dev.py'):
|
||||
current_time = time.time()
|
||||
if current_time - self.last_restart > 1: # Prevent rapid restarts
|
||||
print(f"Detected change in {event.src_path}, restarting...")
|
||||
self.restart_app()
|
||||
self.last_restart = current_time
|
||||
|
||||
def start_app(self):
|
||||
env = os.environ.copy()
|
||||
env['FLASK_ENV'] = 'development'
|
||||
self.process = subprocess.Popen([sys.executable, 'run.py'], env=env)
|
||||
|
||||
def restart_app(self):
|
||||
if self.process:
|
||||
self.process.terminate()
|
||||
self.process.wait()
|
||||
self.start_app()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
path = '.'
|
||||
event_handler = Reloader()
|
||||
observer = Observer()
|
||||
observer.schedule(event_handler, path, recursive=True)
|
||||
observer.start()
|
||||
|
||||
try:
|
||||
while True:
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
observer.stop()
|
||||
observer.join()
|
||||
@@ -1,23 +1,24 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
frontend:
|
||||
build: ./frontend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./frontend:/app
|
||||
- /app/node_modules
|
||||
environment:
|
||||
- VITE_API_URL=http://192.168.1.111:5000 # Replace with your host machine's IP
|
||||
- CHOKIDAR_USEPOLLING=true
|
||||
|
||||
backend:
|
||||
build: ./backend
|
||||
ports:
|
||||
- "5000:5000"
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- backend_data:/app/data
|
||||
frontend:
|
||||
build: ./frontend
|
||||
ports:
|
||||
- '3000:3000'
|
||||
volumes:
|
||||
- ./frontend:/app
|
||||
- /app/node_modules
|
||||
environment:
|
||||
- VITE_API_URL=http://192.168.1.111:5000 # Replace with your host machine's IP
|
||||
- CHOKIDAR_USEPOLLING=true
|
||||
|
||||
backend:
|
||||
build: ./backend
|
||||
ports:
|
||||
- '5000:5000'
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- backend_data:/app/data
|
||||
environment:
|
||||
- FLASK_ENV=development
|
||||
volumes:
|
||||
backend_data:
|
||||
backend_data:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user