diff --git a/.player_heartbeat b/.player_heartbeat new file mode 100644 index 0000000..830af92 --- /dev/null +++ b/.player_heartbeat @@ -0,0 +1 @@ +1768679079.4526675 \ No newline at end of file diff --git a/New.txt b/New.txt index 65fc06f..e69de29 100644 --- a/New.txt +++ b/New.txt @@ -1,68 +0,0 @@ -[INFO ] ✓ Playlist is up to date -[WARNING] Deprecated property "" of object "" has been set, it will be removed in a future version -[WARNING] Deprecated property "" of object "" was accessed, it will be removed in a future version - /home/pi/Desktop/Kiwy-Signage/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py:1097: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.0.121'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings - warnings.warn( -[DEBUG ] [https ]//192.168.0.121:443 "POST /api/auth/verify HTTP/1.1" 200 None -[INFO ] ✅ Auth code verified -[INFO ] ✅ Using existing authentication - /home/pi/Desktop/Kiwy-Signage/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py:1097: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.0.121'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings - warnings.warn( -[DEBUG ] [https ]//192.168.0.121:443 "POST /api/player-feedback HTTP/1.1" 200 None -start.sh: line 212: 16035 Killed python3 main.py -[2026-01-17 21:31:57] ❌ Player process crashed or stopped (PID: 16035) -[2026-01-17 21:31:57] ⏳ Waiting 5s before restart... -[2026-01-17 21:32:02] -[2026-01-17 21:32:02] ========================================== -[2026-01-17 21:32:02] ▶️ Starting player (attempt #2) -[2026-01-17 21:32:02] ========================================== -[2026-01-17 21:32:02] Player PID: 16376 -[INFO ] [Logger ] Record log in /home/pi/.kivy/logs/kivy_26-01-17_43.txt -[INFO ] [Kivy ] v2.3.1 -[INFO ] [Kivy ] Installed at "/home/pi/Desktop/Kiwy-Signage/.venv/lib/python3.13/site-packages/kivy/__init__.py" -[INFO ] [Python ] v3.13.5 (main, Jun 25 2025, 18:55:22) [GCC 14.2.0] -[INFO ] [Python ] Interpreter at "/home/pi/Desktop/Kiwy-Signage/.venv/bin/python3" -[INFO ] [Logger ] Purge log fired. Processing... -[INFO ] [Logger ] Purge finished! - /home/pi/Desktop/Kiwy-Signage/src/main.py:1868: DeprecationWarning: There is no current event loop - loop = asyncio.get_event_loop() -[DEBUG ] [Using selector] EpollSelector -WARNING: running xinput against an Xwayland server. See the xinput man page for details. -WARNING: running xinput against an Xwayland server. See the xinput man page for details. -WARNING: running xinput against an Xwayland server. See the xinput man page for details. -WARNING: running xinput against an Xwayland server. See the xinput man page for details. -WARNING: running xinput against an Xwayland server. See the xinput man page for details. -WARNING: running xinput against an Xwayland server. See the xinput man page for details. -WARNING: running xinput against an Xwayland server. See the xinput man page for details. -WARNING: running xinput against an Xwayland server. See the xinput man page for details. -WARNING: running xinput against an Xwayland server. See the xinput man page for details. -[ERROR ] [Image ] Error loading -[WARNING] ⚠️ SSL verification disabled - NOT recommended for production! -[DEBUG ] [Starting new HTTPS connection (1)] 192.168.0.121:443 - /home/pi/Desktop/Kiwy-Signage/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py:1097: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.0.121'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings - warnings.warn( -[DEBUG ] [https ]//192.168.0.121:443 "POST /api/auth/verify HTTP/1.1" 200 None -[INFO ] ✅ Auth code verified -[INFO ] ✅ Using existing authentication -[INFO ] [Fetching playlist from] https://192.168.0.121:443/api/playlists/1 - /home/pi/Desktop/Kiwy-Signage/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py:1097: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.0.121'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings - warnings.warn( -[DEBUG ] [https ]//192.168.0.121:443 "GET /api/playlists/1 HTTP/1.1" 200 None -[INFO ] [✅ Playlist received (version] 33) -[INFO ] [📊 Playlist versions - Server] v33, Local: v33 -[INFO ] ✓ Playlist is up to date -[WARNING] Deprecated property "" of object "" has been set, it will be removed in a future version -[WARNING] Deprecated property "" of object "" was accessed, it will be removed in a future version - /home/pi/Desktop/Kiwy-Signage/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py:1097: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.0.121'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings - warnings.warn( -[DEBUG ] [https ]//192.168.0.121:443 "POST /api/auth/verify HTTP/1.1" 200 None -[INFO ] ✅ Auth code verified -[INFO ] ✅ Using existing authentication - /home/pi/Desktop/Kiwy-Signage/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py:1097: InsecureRequestWarning: Unverified HTTPS request is being made to host '192.168.0.121'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings - warnings.warn( -[DEBUG ] [https ]//192.168.0.121:443 "POST /api/player-feedback HTTP/1.1" 200 None -start.sh: line 212: 16376 Killed python3 main.py -[2026-01-17 21:32:32] ❌ Player process crashed or stopped (PID: 16376) -[2026-01-17 21:32:32] ⏳ Waiting 5s before restart... -^C[2026-01-17 21:32:33] 🛑 Watchdog received stop signal -pi@rpi-tvcanba1:~/Desktop/Kiwy-Signage $ diff --git a/media/edited_media/2026efvev-1428673176_e_v1.jpg b/media/edited_media/2026efvev-1428673176_e_v1.jpg new file mode 100644 index 0000000..804e6fb Binary files /dev/null and b/media/edited_media/2026efvev-1428673176_e_v1.jpg differ diff --git a/media/edited_media/2026efvev-1428673176_e_v1_metadata.json b/media/edited_media/2026efvev-1428673176_e_v1_metadata.json new file mode 100644 index 0000000..f4842fc --- /dev/null +++ b/media/edited_media/2026efvev-1428673176_e_v1_metadata.json @@ -0,0 +1,8 @@ +{ + "time_of_modification": "2026-01-17T21:40:13.194566", + "original_name": "2026efvev-1428673176.jpg", + "new_name": "2026efvev-1428673176_e_v1.jpg", + "original_path": "/home/pi/Desktop/Kiwy-Signage/media/2026efvev-1428673176.jpg", + "version": 1, + "user_card_data": "0007206239" +} \ No newline at end of file diff --git a/src/edit_popup.py b/src/edit_popup.py index 9405b89..d914815 100644 --- a/src/edit_popup.py +++ b/src/edit_popup.py @@ -341,10 +341,14 @@ class EditPopup(Popup): # NOW show saving popup AFTER everything is done def show_saving_and_dismiss(dt): - # Create label with background + # Create label with background showing detailed save status + save_msg = ( + 'Saved locally!\n' + 'Uploading to server...' + ) save_label = Label( - text='Saved! Reloading player...', - font_size='36sp', + text=save_msg, + font_size='24sp', color=(1, 1, 1, 1), bold=True ) @@ -352,7 +356,7 @@ class EditPopup(Popup): saving_popup = Popup( title='', content=save_label, - size_hint=(0.8, 0.3), + size_hint=(0.85, 0.4), auto_dismiss=False, separator_height=0, background_color=(0.2, 0.7, 0.2, 0.95) # Green background @@ -360,13 +364,23 @@ class EditPopup(Popup): saving_popup.open() Logger.info("EditPopup: Saving confirmation popup opened") - # Dismiss both popups after 2 seconds + # Update message after 3 seconds to show upload is happening + def update_message(dt): + if saving_popup: + save_label.text = ( + '✓ Saved to device\n' + 'Upload in progress...' + ) + + Clock.schedule_once(update_message, 3.0) + + # Dismiss both popups after 4 seconds def dismiss_all(dt): saving_popup.dismiss() Logger.info(f"EditPopup: Dismissing to resume playback...") self.dismiss() - Clock.schedule_once(dismiss_all, 2.0) + Clock.schedule_once(dismiss_all, 4.0) # Small delay to ensure UI is ready, then show popup Clock.schedule_once(show_saving_and_dismiss, 0.1) @@ -420,7 +434,8 @@ class EditPopup(Popup): # Get authenticated instance auth = get_auth_instance() if not auth or not auth.is_authenticated(): - Logger.warning("EditPopup: Cannot upload - not authenticated (server will not receive edited media)") + Logger.warning("EditPopup: Cannot upload - not authenticated (edited media saved locally only)") + Logger.warning("EditPopup: Server will NOT receive this edit") return False server_url = auth.auth_data.get('server_url') @@ -434,60 +449,76 @@ class EditPopup(Popup): with open(metadata_path, 'r') as meta_file: metadata = json.load(meta_file) - # Prepare upload URL + # Prepare upload URL - send to the original file endpoint upload_url = f"{server_url}/api/player-edit-media" headers = {'Authorization': f'Bearer {auth_code}'} + # Add the original filename to metadata so server knows which file was edited + metadata['original_filename'] = os.path.basename(metadata['original_path']) + # Prepare file and data for upload with open(image_path, 'rb') as img_file: files = { - 'image_file': (metadata['new_name'], img_file, 'image/jpeg') + 'image_file': (metadata['original_filename'], img_file, 'image/jpeg') } # Send metadata as JSON string in form data data = { - 'metadata': json.dumps(metadata) + 'metadata': json.dumps(metadata), + 'original_file': metadata['original_filename'] } - Logger.info(f"EditPopup: Uploading edited media to {upload_url}") - response = requests.post(upload_url, headers=headers, files=files, data=data, timeout=30) + Logger.info(f"EditPopup: 📤 Uploading edited media to {upload_url}") + Logger.info(f"EditPopup: - Original file: {metadata['original_filename']}") + Logger.info(f"EditPopup: - Edited image: {image_path}") + Logger.info(f"EditPopup: - Metadata: {metadata_path}") - if response.status_code == 200: - response_data = response.json() - Logger.info(f"EditPopup: ✅ Successfully uploaded edited media to server: {response_data}") + try: + response = requests.post(upload_url, headers=headers, files=files, data=data, timeout=30) - # Delete local files after successful upload - try: - if os.path.exists(image_path): - os.remove(image_path) - Logger.info(f"EditPopup: Deleted local image file: {os.path.basename(image_path)}") + if response.status_code == 200: + response_data = response.json() + Logger.info(f"EditPopup: ✅ Successfully uploaded edited media to server") + Logger.info(f"EditPopup: Server response: {response_data}") - if os.path.exists(metadata_path): - os.remove(metadata_path) - Logger.info(f"EditPopup: Deleted local metadata file: {os.path.basename(metadata_path)}") + # DO NOT delete local files - keep them as backup + # In case the server doesn't process them, we want to keep the edits locally + Logger.info(f"EditPopup: ✓ Keeping local edited files as backup:") + Logger.info(f" - Image: {image_path}") + Logger.info(f" - Metadata: {metadata_path}") - Logger.info("EditPopup: ✅ Local edited files cleaned up after successful upload") - except Exception as e: - Logger.warning(f"EditPopup: Could not delete local files: {e}") - - return True - elif response.status_code == 404: - Logger.warning("EditPopup: ⚠️ Upload endpoint not available on server (404) - edited media saved locally only") + return True + elif response.status_code == 404: + Logger.error("EditPopup: ❌ Upload endpoint not found on server (404)") + Logger.error("EditPopup: Server may not support edited media uploads") + Logger.error("EditPopup: Edited media is saved locally only") + return False + elif response.status_code == 401: + Logger.error("EditPopup: ❌ Authentication failed (401) - check auth credentials") + Logger.error("EditPopup: Edited media is saved locally only") + return False + else: + Logger.error(f"EditPopup: ❌ Upload failed with status {response.status_code}") + Logger.error(f"EditPopup: Response: {response.text}") + Logger.error("EditPopup: Edited media is saved locally only") + return False + + except requests.exceptions.Timeout: + Logger.error("EditPopup: ❌ Upload timed out after 30 seconds") + Logger.error("EditPopup: Check network connection") + Logger.error("EditPopup: Edited media is saved locally only") return False - else: - Logger.warning(f"EditPopup: ⚠️ Upload failed with status {response.status_code} - edited media saved locally only") + except requests.exceptions.ConnectionError as e: + Logger.error(f"EditPopup: ❌ Cannot connect to server: {e}") + Logger.error("EditPopup: Check server URL and network connection") + Logger.error("EditPopup: Edited media is saved locally only") return False - except requests.exceptions.Timeout: - Logger.warning("EditPopup: ⚠️ Upload timed out - edited media saved locally only") - return False - except requests.exceptions.ConnectionError: - Logger.warning("EditPopup: ⚠️ Cannot connect to server - edited media saved locally only") - return False except Exception as e: - Logger.warning(f"EditPopup: ⚠️ Upload failed: {e} - edited media saved locally only") + Logger.error(f"EditPopup: ❌ Unexpected error during upload: {e}") import traceback - Logger.debug(f"EditPopup: Upload traceback: {traceback.format_exc()}") + Logger.error(f"EditPopup: Traceback: {traceback.format_exc()}") + Logger.error("EditPopup: Edited media is saved locally only") return False def close_without_saving(self, instance):