22from flask import Flask , render_template , request , Response , redirect , url_for , send_from_directory , flash
33import json
44import os
5+ import sys
56import subprocess
67from importlib .metadata import version
78
8-
9- # read version for footer
10- #app_version = version('py-config-gs')
9+ # Read version for footer
1110with open ('version.txt' , 'r' ) as f :
1211 app_version = f .read ().strip ()
1312
14-
1513# Configure logging
1614logging .basicConfig (level = logging .DEBUG , # Set the log level to DEBUG
1715 format = '%(asctime)s - %(levelname)s - %(message)s' )
3432
3533# Log the SETTINGS_FILE path
3634logger .info (f'Settings file path: { SETTINGS_FILE } ' )
35+
3736logger .info (f'App version: { app_version } ' )
3837
3938# Load settings.json
4948logger .debug (f'VIDEO_DIR is set to: { VIDEO_DIR } ' )
5049
5150def stream_journal ():
52- """Stream journalctl output in real-time."""
53- process = subprocess .Popen (
54- ['journalctl' , '-f' ],
55- stdout = subprocess .PIPE ,
56- stderr = subprocess .PIPE ,
57- text = True
58- )
59-
60- while True :
61- output = process .stdout .readline ()
62- if output :
63- yield f"data: { output } \n \n "
64- else :
65- break
66-
51+ if os .getenv ('FLASK_ENV' ) != 'development' :
52+ """Stream journalctl output in real-time."""
53+ process = subprocess .Popen (
54+ ['journalctl' , '-f' ],
55+ stdout = subprocess .PIPE ,
56+ stderr = subprocess .PIPE ,
57+ text = True
58+ )
59+
60+ while True :
61+ output = process .stdout .readline ()
62+ if output :
63+ yield f"data: { output } \n \n "
64+ else :
65+ break
66+ else :
67+ logger .info ('No data in DEVELOPMENT mode' )
68+ yield "data: No data in DEVELOPMENT mode\n \n " # Send as part of stream instead of flashing
69+
6770@app .route ('/journal' )
6871def journal ():
6972 return render_template ('journal.html' , version = app_version )
@@ -74,18 +77,18 @@ def stream():
7477
7578@app .route ('/' )
7679def home ():
77- # List of services that you want to control
78- services = ['openipc' ,"wifibroadcast.service" ]
80+ services = ['openipc' , "wifibroadcast.service" ]
7981 service_statuses = {}
82+
83+ # flash(f'Starting up...', 'info')
8084
81- # Fetches the current status (enabled/disabled) for each service.
82- for service in services :
83- # Check if the service is enabled or disabled
84- result = subprocess .run (['systemctl' , 'is-enabled' , service ], stdout = subprocess .PIPE , stderr = subprocess .PIPE )
85- status = result .stdout .decode ('utf-8' ).strip ()
86- service_statuses [service ] = status
85+ if os .getenv ('FLASK_ENV' ) != 'development' :
86+ for service in services :
87+ result = subprocess .run (['systemctl' , 'is-enabled' , service ], stdout = subprocess .PIPE , stderr = subprocess .PIPE )
88+ status = result .stdout .decode ('utf-8' ).strip ()
89+ service_statuses [service ] = status
8790
88- return render_template ('home.html' , config_files = config_files , version = app_version , services = service_statuses )
91+ return render_template ('home.html' , config_files = config_files , version = app_version , services = service_statuses )
8992
9093@app .route ('/edit/<filename>' , methods = ['GET' , 'POST' ])
9194def edit (filename ):
@@ -117,13 +120,12 @@ def videos():
117120 video_files = [f for f in os .listdir (VIDEO_DIR ) if f .endswith (('.mp4' , '.mkv' , '.avi' ))]
118121 logger .debug (f'VIDEO_DIR: { VIDEO_DIR } ' )
119122 logger .debug (f'Video files found: { video_files } ' )
123+ flash (f'Loading from VIDEO_DIR: { VIDEO_DIR } ' ,'info' )
120124 return render_template ('videos.html' , video_files = video_files , version = app_version )
121125
122-
123126@app .route ('/play/<filename>' )
124127def play (filename ):
125128 try :
126- # Ensure the file exists in the VIDEO_DIR and is served from there
127129 return send_from_directory (VIDEO_DIR , filename )
128130 except FileNotFoundError :
129131 logger .error (f'Video file not found: { filename } ' )
@@ -132,11 +134,17 @@ def play(filename):
132134@app .route ('/temperature' )
133135def get_temperature ():
134136 try :
135- soc_temp = int (open ('/sys/class/thermal/thermal_zone0/temp' ).read ().strip ()) / 1000.0 # Convert to °C
136- gpu_temp = int (open ('/sys/class/thermal/thermal_zone1/temp' ).read ().strip ()) / 1000.0 # Convert to °C
137- soc_temp_f = (soc_temp * 9 / 5 ) + 32
138- gpu_temp_f = (gpu_temp * 9 / 5 ) + 32
139-
137+ soc_temp = 0
138+ gpu_temp = 0
139+ soc_temp_f = 0
140+ gpu_temp_f = 0
141+
142+ if os .getenv ('FLASK_ENV' ) != 'development' :
143+ soc_temp = int (open ('/sys/class/thermal/thermal_zone0/temp' ).read ().strip ()) / 1000.0 # Convert to °C
144+ gpu_temp = int (open ('/sys/class/thermal/thermal_zone1/temp' ).read ().strip ()) / 1000.0 # Convert to °C
145+ soc_temp_f = (soc_temp * 9 / 5 ) + 32
146+ gpu_temp_f = (gpu_temp * 9 / 5 ) + 32
147+
140148 return {
141149 'soc_temperature' : f"{ soc_temp :.1f} " ,
142150 'soc_temperature_f' : f"{ soc_temp_f :.1f} " ,
@@ -164,16 +172,13 @@ def backup():
164172def run_command ():
165173 selected_command = request .form .get ('command' )
166174
167- # Construct the first command based on the dropdown value
168175 cli_command = f"echo cli -s { selected_command } > /dev/udp/localhost/14550"
169176 logger .debug (f'Running command: { cli_command } ' )
170177 flash (f'Running command: { cli_command } ' , 'info' )
171178
172- # Run the commands
173179 subprocess .run (cli_command , shell = True )
174180 subprocess .run ("echo killall -1 majestic > /dev/udp/localhost/14550" , shell = True )
175181
176- # Redirect back to the home page after the commands are run
177182 return redirect (url_for ('home' ))
178183
179184@app .route ('/service_action' , methods = ['POST' ])
@@ -199,7 +204,6 @@ def service_action():
199204
200205 return redirect (url_for ('home' ))
201206
202- # Function to check allowed file extensions
203207def allowed_file (filename ):
204208 return '.' in filename and filename .rsplit ('.' , 1 )[1 ].lower () in ALLOWED_EXTENSIONS
205209
@@ -220,8 +224,50 @@ def upload_file():
220224 return redirect (url_for ('home' ))
221225 return render_template ('upload.html' ) # A separate template for file upload
222226
223- def main ():
224- app .run (host = '0.0.0.0' , port = SERVER_PORT )
227+ @app .route ('/settings' , methods = ['GET' , 'POST' ])
228+ def settings ():
229+ # Load settings
230+ with open (SETTINGS_FILE , 'r' ) as f :
231+ settings = json .load (f )
232+
233+ # Initialize config_files from the loaded settings
234+ config_files = settings ['config_files' ]
235+
236+ if request .method == 'POST' :
237+ # Get data from the form
238+ config_files = request .form .getlist ('config_files' )
239+ video_dir = request .form .get ('VIDEO_DIR' )
240+ server_port = request .form .get ('SERVER_PORT' )
241+
242+ # Create a structured dictionary for saving
243+ settings_data = {
244+ "config_files" : [
245+ {"name" : config_files [i ], "path" : request .form [f'path_{ i } ' ]}
246+ for i in range (len (config_files ))
247+ ],
248+ "VIDEO_DIR" : video_dir ,
249+ "SERVER_PORT" : int (server_port ) # Ensure it's an integer
250+ }
251+
252+ # Save the settings to JSON
253+ with open (SETTINGS_FILE , 'w' ) as f :
254+ json .dump (settings_data , f , indent = 4 )
255+ logger .debug ('Updated settings saved.' )
256+
257+ # Restart the Flask app
258+ os .execv (sys .executable , ['python' ] + sys .argv )
259+
260+ return redirect (url_for ('home' ))
261+
262+ return render_template ('settings.html' , config_files = config_files , settings = settings , version = app_version )
263+
264+
225265
226266if __name__ == '__main__' :
227- main ()
267+ # Load settings to get SERVER_PORT and debug mode from the settings file.
268+ with open (SETTINGS_FILE , 'r' ) as f :
269+ settings = json .load (f )
270+
271+ SERVER_PORT = settings ['SERVER_PORT' ]
272+ DEBUG_MODE = os .getenv ('FLASK_ENV' ) == 'development'
273+ app .run (port = SERVER_PORT , debug = DEBUG_MODE , host = '0.0.0.0' )
0 commit comments