diff --git a/tkinter_app/resources/log.txt b/tkinter_app/resources/log.txt index 7d29791..4f381bf 100644 --- a/tkinter_app/resources/log.txt +++ b/tkinter_app/resources/log.txt @@ -2429,3 +2429,553 @@ [INFO] [SignageApp] No playlist updates available [INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) [INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 16:14:39 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1018, Mode: fit, Offset: (281, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Playing media: trans_cindrel_4.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/trans_cindrel_4.jpg +2025-08-23 16:14:50 - STARTED: trans_cindrel_4.jpg +[INFO] [SignageApp] Successfully displayed image: trans_cindrel_4.jpg (Original: (4000, 3000), Screen: 1920x1018, Mode: fit, Offset: (281, 0)) +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +2025-08-23 16:15:01 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No playlist updates available +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1018, Mode: fit, Offset: (281, 0)) +[INFO] [SignageApp] Playing media: trans_cindrel_4.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/trans_cindrel_4.jpg +2025-08-23 16:15:13 - STARTED: trans_cindrel_4.jpg +[INFO] [SignageApp] Successfully displayed image: trans_cindrel_4.jpg (Original: (4000, 3000), Screen: 1920x1018, Mode: fit, Offset: (281, 0)) +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +2025-08-23 16:15:24 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No playlist updates available +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1018, Mode: fit, Offset: (281, 0)) +[INFO] [SignageApp] Media paused +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 16:18:39 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Media paused +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 16:24:29 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Media paused +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 16:28:43 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Playing media: trans_cindrel_4.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/trans_cindrel_4.jpg +2025-08-23 16:28:55 - STARTED: trans_cindrel_4.jpg +[INFO] [SignageApp] Successfully displayed image: trans_cindrel_4.jpg (Original: (4000, 3000), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] Media paused +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 16:41:13 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Media paused +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 17:07:13 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Playing media: trans_cindrel_4.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/trans_cindrel_4.jpg +2025-08-23 17:07:24 - STARTED: trans_cindrel_4.jpg +[INFO] [SignageApp] Successfully displayed image: trans_cindrel_4.jpg (Original: (4000, 3000), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +2025-08-23 17:07:36 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No playlist updates available +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 17:08:21 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Media paused +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 17:14:27 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Media paused +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 17:33:48 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1080, Mode: fit, Offset: (240, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Media paused +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Configuration loaded: server=digi-signage.moto-adv.com, host=tv-terasa, quick=8887779, port=8880 +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] No new playlist on the server. Local version: 29, Server version: 29 +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Found fallback playlist with 2 items +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Initializing with settings: server=digi-signage.moto-adv.com, host=tv-terasa, port=8880 +[INFO] [SignageApp] Attempting to connect to server... +[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'} +[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$UQzlEHNWudAB4P08Le3YJeWHrZHJkWL44kRQpZ53kt.fDLTcrPzGm', 'playlist': [{'duration': 10, 'file_name': 'Cindrel_1.jpg', 'url': 'http://digi-signage.moto-adv.com/media/Cindrel_1.jpg'}, {'duration': 10, 'file_name': 'trans_cindrel_4.jpg', 'url': 'http://digi-signage.moto-adv.com/media/trans_cindrel_4.jpg'}], 'playlist_version': 29} +[INFO] [SignageApp] Fetched updated playlist from server. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] Server playlist found with 2 items, version 29 +[INFO] [SignageApp] python_functions: Starting media file download... +[INFO] [SignageApp] python_functions: File Cindrel_1.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: File trans_cindrel_4.jpg already exists. Skipping download. +[INFO] [SignageApp] python_functions: Starting save_local_playlist function. +[INFO] [SignageApp] python_functions: Updated local playlist with server data. +[INFO] [SignageApp] python_functions: Finished save_local_playlist function. +[INFO] [SignageApp] python_functions: Finished media file download and updated local playlist. +[INFO] [SignageApp] python_functions: Updated playlist version in app_config.txt to 29. +[INFO] [SignageApp] python_functions: Starting load_local_playlist function. +[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': 'Cindrel_1.jpg', 'url': 'static/resurse/Cindrel_1.jpg', 'duration': 10}, {'file_name': 'trans_cindrel_4.jpg', 'url': 'static/resurse/trans_cindrel_4.jpg', 'duration': 10}], 'version': 29} +[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully. +[INFO] [SignageApp] Successfully loaded 2 items from server +[INFO] [SignageApp] Playing media: Cindrel_1.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/Cindrel_1.jpg +2025-08-23 17:43:13 - STARTED: Cindrel_1.jpg +[INFO] [SignageApp] Successfully displayed image: Cindrel_1.jpg (Original: (4096, 3072), Screen: 1920x1018, Mode: fit, Offset: (281, 0)) +[INFO] [SignageApp] Starting Simple Tkinter Media Player +[INFO] [SignageApp] Media paused +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] python_functions: Starting load_config function. +[INFO] [SignageApp] python_functions: Configuration file loaded successfully. +[INFO] [SignageApp] Application exit requested diff --git a/tkinter_app/src/__pycache__/settings_screen.cpython-311.pyc b/tkinter_app/src/__pycache__/settings_screen.cpython-311.pyc index bdd2def..00636b5 100644 Binary files a/tkinter_app/src/__pycache__/settings_screen.cpython-311.pyc and b/tkinter_app/src/__pycache__/settings_screen.cpython-311.pyc differ diff --git a/tkinter_app/src/tkinter_simple_player_old.py b/tkinter_app/src/tkinter_simple_player_old.py deleted file mode 100644 index 2c0e364..0000000 --- a/tkinter_app/src/tkinter_simple_player_old.py +++ /dev/null @@ -1,934 +0,0 @@ -import tkinter as tk -from tkinter import ttk, messagebox, simpledialog -import threading -import time -import os -import json -import datetime -from pathlib import Path -import subprocess -import sys -import requests # Required for server communication -import queue -import vlc # For video playback with hardware acceleration - -# Try importing PIL but provide fallback -try: - from PIL import Image, ImageTk - PIL_AVAILABLE = True -except ImportError: - PIL_AVAILABLE = False - print("WARNING: PIL not available. Image display functionality will be limited.") - -# Import existing functions -from python_functions import ( - load_local_playlist, download_media_files, clean_unused_files, - save_local_playlist, update_config_playlist_version, fetch_server_playlist, - load_config -) -from logging_config import Logger - -# Import virtual keyboard components -from virtual_keyboard import VirtualKeyboard, TouchOptimizedEntry, TouchOptimizedButton - -# Update the config file path to use the resources directory -CONFIG_FILE = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources', 'app_config.txt') - -from player_app import SimpleMediaPlayerApp - - def setup_window(self): - """Configure the main window""" - self.root.title("Simple Signage Player") - self.root.configure(bg='black') - - # Load window size from config - try: - config = load_config() - width = int(config.get('screen_w', 1920)) - height = int(config.get('screen_h', 1080)) - # Load scaling mode preference - self.scaling_mode = config.get('scaling_mode', 'fit') - except: - width, height = 800, 600 # Fallback size if config fails - self.scaling_mode = 'fit' # Default scaling mode - - self.root.geometry(f"{width}x{height}") - self.root.attributes('-fullscreen', True) - - # Bind events - self.root.bind('', self.on_key_press) - self.root.bind('', self.on_mouse_click) - self.root.bind('', self.on_mouse_motion) - self.root.focus_set() - - def setup_ui(self): - """Create the user interface""" - # Main content area - make sure it's black and fill the entire window - self.content_frame = tk.Frame(self.root, bg='black') - self.content_frame.pack(fill=tk.BOTH, expand=True) - - # Image display - expand to fill the entire window - self.image_label = tk.Label(self.content_frame, bg='black') - self.image_label.pack(fill=tk.BOTH, expand=True) - - # Status label - hidden by default - self.status_label = tk.Label( - self.content_frame, - bg='black', - fg='white', - font=('Arial', 24), - text="" - ) - # Don't place the status label by default to keep it hidden - - # Control panel - self.create_control_panel() - self.show_controls() - self.schedule_hide_controls() - - def create_control_panel(self): - """Create touch-optimized control panel with larger buttons""" - # Create control frame with larger size for touch - self.control_frame = tk.Frame( - self.root, - bg='#1a1a1a', # Dark background - bd=2, - relief=tk.RAISED, - padx=15, - pady=15 - ) - self.control_frame.place(relx=0.98, rely=0.98, anchor='se') - - # Touch-optimized button configuration - button_config = { - 'bg': '#333333', - 'fg': 'white', - 'activebackground': '#555555', - 'activeforeground': 'white', - 'relief': tk.FLAT, - 'borderwidth': 0, - 'width': 10, # Larger for touch - 'height': 3, # Larger for touch - 'font': ('Segoe UI', 10, 'bold'), # Larger font - 'cursor': 'hand2' - } - - # Previous button - self.prev_btn = tk.Button( - self.control_frame, - text="⏮ Prev", - command=self.previous_media, - **button_config - ) - self.prev_btn.grid(row=0, column=0, padx=5) - - # Play/Pause button - self.play_pause_btn = tk.Button( - self.control_frame, - text="⏸ Pause" if not self.is_paused else "▶ Play", - command=self.toggle_play_pause, - bg='#27ae60', # Green for play/pause - activebackground='#35d974', - **{k: v for k, v in button_config.items() if k not in ['bg', 'activebackground']} - ) - self.play_pause_btn.grid(row=0, column=1, padx=5) - - # Next button - self.next_btn = tk.Button( - self.control_frame, - text="Next ⏭", - command=self.next_media, - **button_config - ) - self.next_btn.grid(row=0, column=2, padx=5) - - # Settings button - self.settings_btn = tk.Button( - self.control_frame, - text="⚙️ Settings", - command=self.open_settings, - bg='#9b59b6', # Purple for settings - activebackground='#bb8fce', - **{k: v for k, v in button_config.items() if k not in ['bg', 'activebackground']} - ) - self.settings_btn.grid(row=0, column=3, padx=5) - - # Exit button with special styling - self.exit_btn = tk.Button( - self.control_frame, - text="❌ EXIT", - command=self.show_exit_dialog, - bg='#e74c3c', # Red background - fg='white', - activebackground='#ec7063', - activeforeground='white', - relief=tk.FLAT, - borderwidth=0, - width=8, - height=3, - font=('Segoe UI', 10, 'bold'), - cursor='hand2' - ) - self.exit_btn.grid(row=0, column=4, padx=5) - - # Add touch feedback to all buttons - for button in [self.prev_btn, self.play_pause_btn, self.next_btn, - self.settings_btn, self.exit_btn]: - self.add_touch_feedback_to_control_button(button) - - def scale_image_to_screen(self, img, screen_width, screen_height, mode='fit'): - """ - Scale image to screen with different modes: - - 'fit': Maintain aspect ratio, add black bars if needed (letterbox/pillarbox) - - 'fill': Maintain aspect ratio, crop if needed to fill entire screen - - 'stretch': Ignore aspect ratio, stretch to fill entire screen - """ - img_width, img_height = img.size - - if mode == 'stretch': - # Stretch to fill entire screen, ignoring aspect ratio - return img.resize((screen_width, screen_height), Image.LANCZOS), (0, 0) - - elif mode == 'fill': - # Maintain aspect ratio, crop to fill entire screen - screen_ratio = screen_width / screen_height - img_ratio = img_width / img_height - - if img_ratio > screen_ratio: - # Image is wider - scale by height and crop width - new_height = screen_height - new_width = int(screen_height * img_ratio) - x_offset = (screen_width - new_width) // 2 - y_offset = 0 - else: - # Image is taller - scale by width and crop height - new_width = screen_width - new_height = int(screen_width / img_ratio) - x_offset = 0 - y_offset = (screen_height - new_height) // 2 - - # Resize and crop - img_resized = img.resize((new_width, new_height), Image.LANCZOS) - - # Create final image and paste (this will crop automatically) - final_img = Image.new('RGB', (screen_width, screen_height), 'black') - - # Calculate crop area if image is larger than screen - if new_width > screen_width: - crop_x = (new_width - screen_width) // 2 - img_resized = img_resized.crop((crop_x, 0, crop_x + screen_width, new_height)) - x_offset = 0 - if new_height > screen_height: - crop_y = (new_height - screen_height) // 2 - img_resized = img_resized.crop((0, crop_y, new_width, crop_y + screen_height)) - y_offset = 0 - - final_img.paste(img_resized, (x_offset, y_offset)) - return final_img, (x_offset, y_offset) - - else: # mode == 'fit' (default) - # Maintain aspect ratio, add black bars if needed - screen_ratio = screen_width / screen_height - img_ratio = img_width / img_height - - if img_ratio > screen_ratio: - # Image is wider than screen - fit to width - new_width = screen_width - new_height = int(screen_width / img_ratio) - else: - # Image is taller than screen - fit to height - new_height = screen_height - new_width = int(screen_height * img_ratio) - - # Resize image - img_resized = img.resize((new_width, new_height), Image.LANCZOS) - - # Create black background and center the image - final_img = Image.new('RGB', (screen_width, screen_height), 'black') - x_offset = (screen_width - new_width) // 2 - y_offset = (screen_height - new_height) // 2 - final_img.paste(img_resized, (x_offset, y_offset)) - - return final_img, (x_offset, y_offset) - - def add_touch_feedback_to_control_button(self, button): - """Add touch feedback effects to control panel buttons""" - original_bg = button.cget('bg') - - def on_press(e): - button.configure(relief=tk.SUNKEN) - - def on_release(e): - button.configure(relief=tk.FLAT) - - def on_enter(e): - button.configure(relief=tk.RAISED) - - def on_leave(e): - button.configure(relief=tk.FLAT) - - button.bind("", on_press) - button.bind("", on_release) - button.bind("", on_enter) - button.bind("", on_leave) - - def initialize_playlist_from_server(self): - """Initialize the playlist from the server on startup with fallback to local playlist""" - # First try to load any existing local playlist as fallback - fallback_playlist = None - try: - local_playlist_data = load_local_playlist() - fallback_playlist = local_playlist_data.get('playlist', []) - if fallback_playlist: - Logger.info(f"Found fallback playlist with {len(fallback_playlist)} items") - except Exception as e: - Logger.warning(f"No fallback playlist available: {e}") - - # Show connection status - self.status_label.config(text="Connecting to server...\nPlease wait") - self.status_label.place(relx=0.5, rely=0.5, anchor='center') - self.root.update() - - # Load configuration - config = load_config() - server = config.get("server_ip", "") - host = config.get("screen_name", "") - quick = config.get("quickconnect_key", "") - port = config.get("port", "") - - Logger.info(f"Initializing with settings: server={server}, host={host}, port={port}") - - if not server or not host or not quick or not port: - Logger.warning("Missing server configuration, using fallback playlist") - self.status_label.place_forget() - self.load_fallback_playlist(fallback_playlist) - return - - # Attempt to fetch server playlist with timeout - server_connection_successful = False - try: - # Add connection timeout and retry logic - Logger.info("Attempting to connect to server...") - self.status_label.config(text="Connecting to server...\nAttempting connection") - self.root.update() - - server_playlist_data = fetch_server_playlist() - server_playlist = server_playlist_data.get('playlist', []) - server_version = server_playlist_data.get('version', 0) - - if server_playlist: - Logger.info(f"Server playlist found with {len(server_playlist)} items, version {server_version}") - server_connection_successful = True - - # Download media files and update local playlist - self.status_label.config(text="Downloading media files...\nPlease wait") - self.root.update() - - download_media_files(server_playlist, server_version) - update_config_playlist_version(server_version) - - # Load the updated local playlist - local_playlist_data = load_local_playlist() - self.playlist = local_playlist_data.get('playlist', []) - - if self.playlist: - Logger.info(f"Successfully loaded {len(self.playlist)} items from server") - self.status_label.place_forget() - self.play_current_media() - return - else: - Logger.warning("Server playlist was empty, falling back to local playlist") - else: - Logger.warning("Server returned empty playlist, falling back to local playlist") - - except requests.exceptions.ConnectTimeout: - Logger.error("Server connection timeout, using fallback playlist") - except requests.exceptions.ConnectionError: - Logger.error("Cannot connect to server, using fallback playlist") - except requests.exceptions.Timeout: - Logger.error("Server request timeout, using fallback playlist") - except Exception as e: - Logger.error(f"Failed to fetch playlist from server: {e}, using fallback playlist") - - # If we reach here, server connection failed - use fallback - if not server_connection_successful: - self.status_label.config(text="Server unavailable\nLoading last playlist...") - self.root.update() - time.sleep(1) # Brief pause to show message - - self.status_label.place_forget() - self.load_fallback_playlist(fallback_playlist) - - def load_fallback_playlist(self, fallback_playlist): - """Load fallback playlist when server is unavailable""" - if fallback_playlist and len(fallback_playlist) > 0: - self.playlist = fallback_playlist - Logger.info(f"Loaded fallback playlist with {len(self.playlist)} items") - self.play_current_media() - else: - Logger.warning("No fallback playlist available, loading demo content") - self.load_demo_or_local_playlist() - - def load_demo_or_local_playlist(self): - """Load either the existing local playlist or demo content""" - # First try to load the local playlist - local_playlist_data = load_local_playlist() - self.playlist = local_playlist_data.get('playlist', []) - - if self.playlist: - Logger.info(f"Loaded existing local playlist with {len(self.playlist)} items") - self.play_current_media() - return - - # If no local playlist, try loading demo content - Logger.info("No local playlist found, loading demo content") - self.create_demo_content() - - if self.playlist: - self.play_current_media() - else: - self.show_no_content_message() - - def create_demo_content(self): - """Create demo content for testing""" - demo_images = [] - - # First check static/resurse folder for any media - static_dir = os.path.join(os.path.dirname(__file__), 'static', 'resurse') - if os.path.exists(static_dir): - for file in os.listdir(static_dir): - if file.lower().endswith(('.jpg', '.jpeg', '.png', '.gif')): - full_path = os.path.join(static_dir, file) - demo_images.append({ - 'file_name': file, - 'url': full_path, - 'duration': 5 - }) - - # If no files found in static/resurse, look in Resurse folder - if not demo_images: - demo_dir = './Resurse' - if os.path.exists(demo_dir): - for file in os.listdir(demo_dir): - if file.lower().endswith(('.jpg', '.jpeg', '.png', '.gif')): - demo_images.append({ - 'file_name': file, - 'url': os.path.join(demo_dir, file), - 'duration': 5 - }) - - if demo_images: - self.playlist = demo_images - Logger.info(f"Created demo playlist with {len(demo_images)} images") - else: - # Create a text-only demo if no images found - self.playlist = [{ - 'file_name': 'Demo Text', - 'url': 'text://Welcome to Tkinter Media Player!\n\nPlease configure server settings', - 'duration': 5 - }] - - def show_no_content_message(self): - """Show message when no content is available""" - self.image_label.config(image='') - self.status_label.config( - text="No media content available.\nPress Settings to configure server connection." - ) - self.status_label.place(relx=0.5, rely=0.5, anchor='center') - - def show_error_message(self, message): - """Show error message""" - self.image_label.config(image='') - self.status_label.config(text=f"Error: {message}") - self.status_label.place(relx=0.5, rely=0.5, anchor='center') - - def play_current_media(self): - """Play the current media item""" - if not self.playlist or self.current_index >= len(self.playlist): - self.show_no_content_message() - return - - media = self.playlist[self.current_index] - file_path = media.get('url', '') - file_name = media.get('file_name', '') - duration = media.get('duration', 10) - - # Handle relative paths by converting to absolute paths - if file_path.startswith('static/resurse/'): - # Convert relative path to absolute - absolute_path = os.path.join(os.path.dirname(__file__), file_path) - file_path = absolute_path - - Logger.info(f"Playing media: {file_name} from {file_path}") - - # Log media start - self.log_event(file_name, "STARTED") - - # Cancel existing timers - self.cancel_timers() - - # Handle different media types - if file_path.startswith('text://'): - self.show_text_content(file_path[7:], duration) - elif file_path.lower().endswith(('.mp4', '.avi', '.mov', '.mkv')): - self.play_video(file_path) - elif os.path.exists(file_path) and file_path.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp')): - self.show_image(file_path, duration) - else: - Logger.error(f"Unsupported or missing media: {file_path}") - self.status_label.config(text=f"Missing or unsupported media:\n{file_name}") - # Schedule next media after short delay - self.auto_advance_timer = self.root.after(5000, self.next_media) - - def play_video(self, file_path): - """Play video file using system VLC as a subprocess for robust hardware acceleration and stability.""" - self.status_label.place_forget() - def run_vlc_subprocess(): - try: - Logger.info(f"Starting system VLC subprocess for video: {file_path}") - # Build VLC command - vlc_cmd = [ - 'cvlc', - '--fullscreen', - '--no-osd', - '--no-video-title-show', - '--play-and-exit', - '--quiet', - file_path - ] - proc = subprocess.Popen(vlc_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - proc.wait() - Logger.info(f"VLC subprocess finished: {file_path}") - except Exception as e: - Logger.error(f"VLC subprocess error: {e}") - finally: - self.root.after_idle(lambda: setattr(self, 'auto_advance_timer', self.root.after(1000, self.next_media))) - threading.Thread(target=run_vlc_subprocess, daemon=True).start() - - def _update_video_frame(self, photo): - """Update video frame from main thread""" - try: - self.image_label.config(image=photo) - self.image_label.image = photo # Keep reference - except Exception as e: - Logger.error(f"Error updating video frame: {e}") - - def _show_video_error(self, error_msg): - """Show video error from main thread""" - try: - self.status_label.config(text=f"Video Error:\n{error_msg}") - self.status_label.place(relx=0.5, rely=0.5, anchor='center') - self.auto_advance_timer = self.root.after(5000, self.next_media) - except Exception as e: - Logger.error(f"Error showing video error: {e}") - self.auto_advance_timer = self.root.after(5000, self.next_media) - - def show_text_content(self, text, duration): - """Display text content""" - self.image_label.config(image='') - self.status_label.config(text=text) - - # Schedule next media - self.auto_advance_timer = self.root.after( - int(duration * 1000), - self.next_media - ) - - def show_image(self, file_path, duration): - """Display an image in full screen, properly fitted to screen size""" - try: - # Hide status label and clear any previous text - self.status_label.place_forget() - self.status_label.config(text="") - - if PIL_AVAILABLE: - # Use PIL for better image handling - img = Image.open(file_path) - original_size = img.size - - # Get actual screen dimensions - screen_width = self.root.winfo_width() - screen_height = self.root.winfo_height() - - # Ensure we have valid screen dimensions - if screen_width <= 1 or screen_height <= 1: - screen_width = 1920 # Default fallback - screen_height = 1080 - - # Scale image using the scaling helper - final_img, offset = self.scale_image_to_screen(img, screen_width, screen_height, self.scaling_mode) - - # Convert to PhotoImage - photo = ImageTk.PhotoImage(final_img) - - # Clear previous image and display new one - self.image_label.config(image=photo) - self.image_label.image = photo # Keep reference - - Logger.info(f"Successfully displayed image: {os.path.basename(file_path)} " - f"(Original: {original_size}, Screen: {screen_width}x{screen_height}, " - f"Mode: {self.scaling_mode}, Offset: {offset})") - else: - # Fall back to basic text display if PIL not available - self.image_label.config(image='') - self.status_label.config(text=f"IMAGE: {os.path.basename(file_path)}\n\n(Install PIL for image display)") - self.status_label.place(relx=0.5, rely=0.5, anchor='center') - Logger.warning("PIL not available - showing text placeholder for image") - - # Schedule next media - self.auto_advance_timer = self.root.after( - int(duration * 1000), - self.next_media - ) - - except Exception as e: - Logger.error(f"Failed to show image {file_path}: {e}") - self.image_label.config(image='') - self.status_label.config(text=f"Image Error:\n{os.path.basename(file_path)}\n{str(e)}") - self.status_label.place(relx=0.5, rely=0.5, anchor='center') - self.auto_advance_timer = self.root.after(5000, self.next_media) - - def next_media(self): - """Move to next media""" - self.cancel_timers() - - if not self.playlist: - return - - self.current_index = (self.current_index + 1) % len(self.playlist) - - # Check for playlist updates at end of cycle - if self.current_index == 0: - threading.Thread(target=self.check_playlist_updates, daemon=True).start() - - self.play_current_media() - - def previous_media(self): - """Move to previous media""" - self.cancel_timers() - - if not self.playlist: - return - - self.current_index = (self.current_index - 1) % len(self.playlist) - self.play_current_media() - - def toggle_play_pause(self): - """Toggle play/pause state""" - self.is_paused = not self.is_paused - - if self.is_paused: - self.play_pause_btn.config(text="▶ Play") - self.cancel_timers() - else: - self.play_pause_btn.config(text="⏸ Pause") - # Resume current media - self.play_current_media() - - Logger.info(f"Media {'paused' if self.is_paused else 'resumed'}") - - def cancel_timers(self): - """Cancel all active timers""" - if self.auto_advance_timer: - self.root.after_cancel(self.auto_advance_timer) - self.auto_advance_timer = None - - def show_controls(self): - """Show control panel""" - if self.control_frame: - self.control_frame.place(relx=0.98, rely=0.98, anchor='se') - - def hide_controls(self): - """Hide control panel""" - if self.control_frame: - self.control_frame.place_forget() - - def schedule_hide_controls(self): - """Schedule hiding controls after delay""" - if self.hide_controls_timer: - self.root.after_cancel(self.hide_controls_timer) - self.hide_controls_timer = self.root.after(10000, self.hide_controls) - - def on_mouse_click(self, event): - """Handle mouse clicks""" - self.show_controls() - self.schedule_hide_controls() - - def on_mouse_motion(self, event): - """Handle mouse motion""" - self.show_controls() - self.schedule_hide_controls() - - def on_key_press(self, event): - """Handle keyboard events""" - key = event.keysym.lower() - - if key == 'f': - self.toggle_fullscreen() - elif key == 'space': - self.toggle_play_pause() - elif key == 'left': - self.previous_media() - elif key == 'right': - self.next_media() - elif key == 'escape': - self.show_exit_dialog() - elif key == '1': - self.set_scaling_mode('fit') - elif key == '2': - self.set_scaling_mode('fill') - elif key == '3': - self.set_scaling_mode('stretch') - elif event.state & 0x4: # Ctrl key pressed - if key == 's': - self.open_settings() - - self.show_controls() - self.schedule_hide_controls() - - def set_scaling_mode(self, mode): - """Change the scaling mode and refresh current media""" - old_mode = self.scaling_mode - self.scaling_mode = mode - Logger.info(f"Scaling mode changed from '{old_mode}' to '{mode}'") - - # Show temporary notification - self.status_label.config(text=f"Scaling Mode: {mode.title()}\n" - f"1=Fit 2=Fill 3=Stretch") - self.status_label.place(relx=0.5, rely=0.05, anchor='center') - - # Hide notification after 2 seconds - self.root.after(2000, lambda: self.status_label.place_forget()) - - # Refresh current media with new scaling - if self.playlist and 0 <= self.current_index < len(self.playlist): - self.cancel_timers() - self.play_current_media() - - def toggle_fullscreen(self): - """Toggle fullscreen mode""" - self.is_fullscreen = not self.is_fullscreen - self.root.attributes('-fullscreen', self.is_fullscreen) - - def open_settings(self): - """Open settings window""" - if hasattr(self, 'settings_window') and self.settings_window and self.settings_window.winfo_exists(): - self.settings_window.lift() - return - - # Pause media playback when opening settings - if not self.is_paused: - self.toggle_play_pause() - - self.settings_window = SettingsWindow(self.root, self) - - # Add a callback to resume playback when the settings window is closed - def on_settings_close(): - if self.is_paused: - self.toggle_play_pause() - - self.settings_window.protocol("WM_DELETE_WINDOW", on_settings_close) - - def show_exit_dialog(self): - """Show modern password-protected exit dialog""" - try: - config = load_config() - quickconnect_key = config.get('quickconnect_key', '') - except: - quickconnect_key = '' - - # Create modern exit dialog - exit_dialog = tk.Toplevel(self.root) - exit_dialog.title("Exit Application") - exit_dialog.geometry("400x200") - exit_dialog.configure(bg='#2d2d2d') - exit_dialog.transient(self.root) - exit_dialog.grab_set() - exit_dialog.resizable(False, False) - - # Center the dialog using helper method - self.center_dialog_on_screen(exit_dialog, 400, 200) - - # Header with icon - header_frame = tk.Frame(exit_dialog, bg='#cc0000', height=60) - header_frame.pack(fill=tk.X) - header_frame.pack_propagate(False) - - icon_label = tk.Label(header_frame, text="⚠", font=('Arial', 20, 'bold'), - fg='white', bg='#cc0000') - icon_label.pack(side=tk.LEFT, padx=15, pady=15) - - title_label = tk.Label(header_frame, text="Exit Application", - font=('Arial', 14, 'bold'), fg='white', bg='#cc0000') - title_label.pack(side=tk.LEFT, pady=15) - - # Content frame - content_frame = tk.Frame(exit_dialog, bg='#2d2d2d', padx=20, pady=20) - content_frame.pack(fill=tk.BOTH, expand=True) - - # Password prompt - prompt_label = tk.Label(content_frame, text="Enter password to exit:", - font=('Arial', 11), fg='white', bg='#2d2d2d') - prompt_label.pack(pady=(0, 10)) - - # Password entry - password_var = tk.StringVar() - password_entry = tk.Entry(content_frame, textvariable=password_var, - font=('Arial', 11), show='*', width=25, - bg='#404040', fg='white', insertbackground='white', - relief=tk.FLAT, bd=5) - password_entry.pack(pady=(0, 15)) - password_entry.focus_set() - - # Button frame - button_frame = tk.Frame(content_frame, bg='#2d2d2d') - button_frame.pack(fill=tk.X) - - def check_password(): - if password_var.get() == quickconnect_key: - exit_dialog.destroy() - self.exit_application() - elif password_var.get(): # Only show error if password was entered - # Show error in red - error_label.config(text="✗ Incorrect password", fg='#ff4444') - password_entry.delete(0, tk.END) - password_entry.focus_set() - - def cancel_exit(): - exit_dialog.destroy() - - # Error label (hidden initially) - error_label = tk.Label(content_frame, text="", font=('Arial', 9), - bg='#2d2d2d') - error_label.pack() - - # Buttons - cancel_btn = tk.Button(button_frame, text="Cancel", command=cancel_exit, - bg='#555555', fg='white', font=('Arial', 10, 'bold'), - relief=tk.FLAT, padx=20, pady=8, width=10) - cancel_btn.pack(side=tk.RIGHT, padx=(10, 0)) - - exit_btn = tk.Button(button_frame, text="Exit", command=check_password, - bg='#cc0000', fg='white', font=('Arial', 10, 'bold'), - relief=tk.FLAT, padx=20, pady=8, width=10) - exit_btn.pack(side=tk.RIGHT) - - # Bind Enter key to check password - password_entry.bind('', lambda e: check_password()) - exit_dialog.bind('', lambda e: cancel_exit()) - - def exit_application(self): - """Exit the application""" - Logger.info("Application exit requested") - self.running = False - self.root.quit() - self.root.destroy() - - def center_dialog_on_screen(self, dialog, width, height): - """Center a dialog window on screen regardless of screen size""" - dialog.update_idletasks() # Ensure geometry is calculated - screen_width = dialog.winfo_screenwidth() - screen_height = dialog.winfo_screenheight() - - # Calculate center position - center_x = int((screen_width - width) / 2) - center_y = int((screen_height - height) / 2) - - # Ensure the dialog doesn't go off-screen on smaller displays - center_x = max(0, min(center_x, screen_width - width)) - center_y = max(0, min(center_y, screen_height - height)) - - dialog.geometry(f"{width}x{height}+{center_x}+{center_y}") - - # Bring to front and focus - dialog.lift() - dialog.focus_force() - - return center_x, center_y - - def check_playlist_updates(self): - """Check for playlist updates from server with fallback protection""" - try: - config = load_config() - local_version = config.get('playlist_version', 0) - - server_playlist_data = fetch_server_playlist() - server_version = server_playlist_data.get('version', 0) - - if server_version > local_version: - Logger.info(f"Updating playlist: {local_version} -> {server_version}") - - # Clean old files - local_playlist_data = load_local_playlist() - clean_unused_files(local_playlist_data.get('playlist', [])) - - # Download new content - download_media_files( - server_playlist_data.get('playlist', []), - server_version - ) - - # Update local playlist - local_playlist_data = load_local_playlist() - self.playlist = local_playlist_data.get('playlist', []) - - # Reset to beginning of playlist - self.current_index = 0 - - Logger.info("Playlist updated successfully") - - # Continue with current media after update - self.play_current_media() - else: - Logger.info("No playlist updates available") - - except requests.exceptions.ConnectTimeout: - Logger.warning("Server connection timeout during update check - continuing with current playlist") - except requests.exceptions.ConnectionError: - Logger.warning("Cannot connect to server during update check - continuing with current playlist") - except requests.exceptions.Timeout: - Logger.warning("Server request timeout during update check - continuing with current playlist") - except Exception as e: - Logger.warning(f"Failed to check playlist updates: {e} - continuing with current playlist") - - def log_event(self, file_name, event): - """Log media events""" - try: - timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') - log_message = f"{timestamp} - {event}: {file_name}\n" - - # Update the log file path to the resources directory - log_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources', 'log.txt') - with open(log_file, 'a') as f: - f.write(log_message) - - except Exception as e: - Logger.error(f"Failed to log event: {e}") - - def start_periodic_checks(self): - """Start periodic playlist checks""" - def check_loop(): - """Background thread for periodic checks""" - while self.running: - try: - time.sleep(300) # Check every 5 minutes - if self.running: - self.check_playlist_updates() - except Exception as e: - Logger.error(f"Error in periodic check: {e}") - - # Start background thread - threading.Thread(target=check_loop, daemon=True).start() - - def run(self): - """Start the application""" - Logger.info("Starting Simple Tkinter Media Player") - try: - self.root.mainloop() - except KeyboardInterrupt: - self.exit_application() - except Exception as e: - Logger.error(f"Application error: {e}") - print(f"Error: {e}") - -