Finalize: working player, automatic playlist version check, server URL fix, and robust playlist update logic
This commit is contained in:
@@ -16,5 +16,5 @@
|
||||
"duration": 5
|
||||
}
|
||||
],
|
||||
"version": 5
|
||||
"version": 0
|
||||
}
|
||||
@@ -1704,3 +1704,558 @@
|
||||
[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: 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_local_playlist function.
|
||||
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 5}
|
||||
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||
[INFO] [SignageApp] Found fallback playlist with 3 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:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||
[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] Loaded fallback playlist with 3 items
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
2025-08-22 22:21:01 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||
[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_local_playlist function.
|
||||
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 0}
|
||||
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||
[INFO] [SignageApp] Found fallback playlist with 3 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:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
2025-08-22 22:33:08 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:33:29 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:33:45 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:33:52 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:34:13 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:34:29 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
2025-08-22 22:34:36 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:34:56 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:35:12 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:35:19 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:35:40 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:35:56 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:36:02 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:36:23 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:36:39 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:36:46 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:37:06 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:37:22 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
2025-08-22 22:37:29 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:37:50 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:38:06 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[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:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:38:13 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:38:33 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:38:49 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:38:56 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:39:17 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:39:33 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:39:40 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:40:00 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:40:16 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
2025-08-22 22:40:23 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:40:43 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1080, Mode: fit, Offset: (96, 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:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No new playlist on the server. Local version: 0, Server version: 0
|
||||
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 0}
|
||||
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||
[INFO] [SignageApp] Found fallback playlist with 3 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:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
2025-08-22 22:46:40 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||
[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=http://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://http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='http', port=80): Max retries exceeded with url: /digi-signage.moto-adv.com:8880/api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NameResolutionError("<urllib3.connection.HTTPConnection object at 0xf57f02d0>: Failed to resolve 'http' ([Errno -2] Name or service not known)"))
|
||||
[INFO] [SignageApp] No new playlist on the server. Local version: 0, Server version: 0
|
||||
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 0}
|
||||
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||
[INFO] [SignageApp] Found fallback playlist with 3 items
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Initializing with settings: server=http://digi-signage.moto-adv.com, host=tv-terasa, port=8880
|
||||
[INFO] [SignageApp] Attempting to connect to server...
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist: HTTPConnectionPool(host='http', port=80): Max retries exceeded with url: /digi-signage.moto-adv.com:8880/api/playlists?hostname=tv-terasa&quickconnect_code=8887779 (Caused by NameResolutionError("<urllib3.connection.HTTPConnection object at 0xf57f0fb0>: Failed to resolve 'http' ([Errno -2] Name or service not known)"))
|
||||
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
2025-08-22 22:47:16 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1080, Mode: fit, Offset: (96, 0))
|
||||
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||
[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:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No new playlist on the server. Local version: 0, Server version: 0
|
||||
[INFO] [SignageApp] python_functions: Starting load_local_playlist function.
|
||||
[INFO] [SignageApp] python_functions: Local playlist loaded: {'playlist': [{'file_name': '1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'url': 'static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg', 'duration': 20}, {'file_name': 'wp2782770-1846651530.jpg', 'url': 'static/resurse/wp2782770-1846651530.jpg', 'duration': 15}, {'file_name': 'SampleVideo_1280x720_1mb.mp4', 'url': 'static/resurse/SampleVideo_1280x720_1mb.mp4', 'duration': 5}], 'version': 0}
|
||||
[INFO] [SignageApp] python_functions: Finished load_local_playlist function successfully.
|
||||
[INFO] [SignageApp] Found fallback playlist with 3 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:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[WARNING] [SignageApp] Server returned empty playlist, falling back to local playlist
|
||||
[INFO] [SignageApp] Loaded fallback playlist with 3 items
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
2025-08-22 22:49:45 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Starting Simple Tkinter Media Player
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:50:05 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:50:22 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:50:29 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:50:49 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:51:06 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:51:13 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:51:34 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:51:50 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:51:57 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:52:18 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:52:34 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
2025-08-22 22:52:41 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:53:03 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:53:19 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:53:26 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:53:47 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:54:03 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:54:10 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:54:31 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[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:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:54:47 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
2025-08-22 22:54:54 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:55:15 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:55:32 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:55:39 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:55:59 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:56:16 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
2025-08-22 22:56:23 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:56:43 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:57:00 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:57:07 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:57:27 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:57:44 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:57:51 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:58:11 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:58:28 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 22:58:35 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:58:55 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:59:12 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
2025-08-22 22:59:19 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 22:59:39 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 22:59:56 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
2025-08-22 23:00:03 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[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:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 23:00:24 - STARTED: wp2782770-1846651530.jpg
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 23:00:40 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
2025-08-22 23:00:48 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[ERROR] [SignageApp] Failed to fetch playlist. Status Code: 522
|
||||
[INFO] [SignageApp] No playlist updates available
|
||||
[INFO] [SignageApp] Playing media: wp2782770-1846651530.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/wp2782770-1846651530.jpg
|
||||
2025-08-22 23:01:09 - STARTED: wp2782770-1846651530.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: wp2782770-1846651530.jpg (Original: (3840, 2400), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] Playing media: SampleVideo_1280x720_1mb.mp4 from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
2025-08-22 23:01:26 - STARTED: SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] Starting system VLC subprocess for video: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] VLC subprocess finished: /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/SampleVideo_1280x720_1mb.mp4
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Playing media: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg from /home/pi/Desktop/tkinter_player/tkinter_app/src/static/resurse/1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Fetching playlist from URL: http://digi-signage.moto-adv.com:8880/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||
2025-08-22 23:01:33 - STARTED: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg
|
||||
[INFO] [SignageApp] Successfully displayed image: 1307306470-nature_wallpaper_hd_hd_nature_3-3828209637.jpg (Original: (1600, 1000), Screen: 1920x1018, Mode: fit, Offset: (146, 0))
|
||||
[INFO] [SignageApp] python_functions: Starting load_config function.
|
||||
[INFO] [SignageApp] python_functions: Configuration file loaded successfully.
|
||||
[INFO] [SignageApp] Application exit requested
|
||||
|
||||
BIN
tkinter_app/src/__pycache__/player_app.cpython-311.pyc
Normal file
BIN
tkinter_app/src/__pycache__/player_app.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
tkinter_app/src/__pycache__/settings_screen.cpython-311.pyc
Normal file
BIN
tkinter_app/src/__pycache__/settings_screen.cpython-311.pyc
Normal file
Binary file not shown.
@@ -9,10 +9,12 @@ import sys
|
||||
# Add the current directory to the path so we can import our modules
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Import the player module
|
||||
from tkinter_simple_player import SimpleMediaPlayerApp
|
||||
|
||||
# Import the player module from player_app.py
|
||||
from player_app import SimpleMediaPlayerApp
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Create and run the player
|
||||
player = SimpleMediaPlayerApp()
|
||||
import tkinter as tk
|
||||
root = tk.Tk()
|
||||
player = SimpleMediaPlayerApp(root)
|
||||
player.run()
|
||||
@@ -0,0 +1,722 @@
|
||||
# player_app.py
|
||||
# Main player application logic moved from tkinter_simple_player.py
|
||||
|
||||
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:
|
||||
from PIL import Image, ImageTk
|
||||
PIL_AVAILABLE = True
|
||||
except ImportError:
|
||||
PIL_AVAILABLE = False
|
||||
print("WARNING: PIL not available. Image display functionality will be limited.")
|
||||
|
||||
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
|
||||
from virtual_keyboard import VirtualKeyboard, TouchOptimizedEntry, TouchOptimizedButton
|
||||
from settings_screen import SettingsWindow
|
||||
|
||||
CONFIG_FILE = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources', 'app_config.txt')
|
||||
|
||||
|
||||
class SimpleMediaPlayerApp:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.running = True
|
||||
self.is_paused = False
|
||||
self.is_fullscreen = True
|
||||
self.playlist = []
|
||||
self.current_index = 0
|
||||
self.scaling_mode = 'fit'
|
||||
self.auto_advance_timer = None
|
||||
self.hide_controls_timer = None
|
||||
self.control_frame = None
|
||||
self.settings_window = None
|
||||
self.content_frame = None
|
||||
self.image_label = None
|
||||
self.status_label = None
|
||||
self.play_pause_btn = None
|
||||
self.prev_btn = None
|
||||
self.next_btn = None
|
||||
self.exit_btn = None
|
||||
self.settings_btn = None
|
||||
self.setup_window()
|
||||
self.setup_ui()
|
||||
# Automatically check for new server playlist on startup
|
||||
try:
|
||||
from python_functions import check_for_new_server_playlist
|
||||
check_for_new_server_playlist()
|
||||
except Exception as e:
|
||||
Logger.error(f"Failed to check for new server playlist: {e}")
|
||||
self.initialize_playlist_from_server()
|
||||
self.start_periodic_checks()
|
||||
|
||||
|
||||
def setup_window(self):
|
||||
self.root.title("Simple Signage Player")
|
||||
self.root.configure(bg='black')
|
||||
try:
|
||||
config = load_config()
|
||||
width = int(config.get('screen_w', 1920))
|
||||
height = int(config.get('screen_h', 1080))
|
||||
self.scaling_mode = config.get('scaling_mode', 'fit')
|
||||
except:
|
||||
width, height = 800, 600
|
||||
self.scaling_mode = 'fit'
|
||||
self.root.geometry(f"{width}x{height}")
|
||||
self.root.attributes('-fullscreen', True)
|
||||
self.root.bind('<Key>', self.on_key_press)
|
||||
self.root.bind('<Button-1>', self.on_mouse_click)
|
||||
self.root.bind('<Motion>', self.on_mouse_motion)
|
||||
self.root.focus_set()
|
||||
|
||||
def setup_ui(self):
|
||||
self.content_frame = tk.Frame(self.root, bg='black')
|
||||
self.content_frame.pack(fill=tk.BOTH, expand=True)
|
||||
self.image_label = tk.Label(self.content_frame, bg='black')
|
||||
self.image_label.pack(fill=tk.BOTH, expand=True)
|
||||
self.status_label = tk.Label(
|
||||
self.content_frame,
|
||||
bg='black',
|
||||
fg='white',
|
||||
font=('Arial', 24),
|
||||
text=""
|
||||
)
|
||||
self.create_control_panel()
|
||||
self.show_controls()
|
||||
self.schedule_hide_controls()
|
||||
|
||||
# --- FULL METHOD BODIES FROM tkinter_simple_player_old.py BELOW ---
|
||||
def create_control_panel(self):
|
||||
"""Create touch-optimized control panel with larger buttons"""
|
||||
self.control_frame = tk.Frame(
|
||||
self.root,
|
||||
bg='#1a1a1a',
|
||||
bd=2,
|
||||
relief=tk.RAISED,
|
||||
padx=15,
|
||||
pady=15
|
||||
)
|
||||
self.control_frame.place(relx=0.98, rely=0.98, anchor='se')
|
||||
button_config = {
|
||||
'bg': '#333333',
|
||||
'fg': 'white',
|
||||
'activebackground': '#555555',
|
||||
'activeforeground': 'white',
|
||||
'relief': tk.FLAT,
|
||||
'borderwidth': 0,
|
||||
'width': 10,
|
||||
'height': 3,
|
||||
'font': ('Segoe UI', 10, 'bold'),
|
||||
'cursor': 'hand2'
|
||||
}
|
||||
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)
|
||||
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',
|
||||
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)
|
||||
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)
|
||||
self.settings_btn = tk.Button(
|
||||
self.control_frame,
|
||||
text="⚙️ Settings",
|
||||
command=self.open_settings,
|
||||
bg='#9b59b6',
|
||||
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)
|
||||
self.exit_btn = tk.Button(
|
||||
self.control_frame,
|
||||
text="❌ EXIT",
|
||||
command=self.show_exit_dialog,
|
||||
bg='#e74c3c',
|
||||
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)
|
||||
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'):
|
||||
img_width, img_height = img.size
|
||||
if mode == 'stretch':
|
||||
return img.resize((screen_width, screen_height), Image.LANCZOS), (0, 0)
|
||||
elif mode == 'fill':
|
||||
screen_ratio = screen_width / screen_height
|
||||
img_ratio = img_width / img_height
|
||||
if img_ratio > screen_ratio:
|
||||
new_height = screen_height
|
||||
new_width = int(screen_height * img_ratio)
|
||||
x_offset = (screen_width - new_width) // 2
|
||||
y_offset = 0
|
||||
else:
|
||||
new_width = screen_width
|
||||
new_height = int(screen_width / img_ratio)
|
||||
x_offset = 0
|
||||
y_offset = (screen_height - new_height) // 2
|
||||
img_resized = img.resize((new_width, new_height), Image.LANCZOS)
|
||||
final_img = Image.new('RGB', (screen_width, screen_height), 'black')
|
||||
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:
|
||||
screen_ratio = screen_width / screen_height
|
||||
img_ratio = img_width / img_height
|
||||
if img_ratio > screen_ratio:
|
||||
new_width = screen_width
|
||||
new_height = int(screen_width / img_ratio)
|
||||
else:
|
||||
new_height = screen_height
|
||||
new_width = int(screen_height * img_ratio)
|
||||
img_resized = img.resize((new_width, new_height), Image.LANCZOS)
|
||||
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):
|
||||
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("<Button-1>", on_press)
|
||||
button.bind("<ButtonRelease-1>", on_release)
|
||||
button.bind("<Enter>", on_enter)
|
||||
button.bind("<Leave>", on_leave)
|
||||
|
||||
def initialize_playlist_from_server(self):
|
||||
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}")
|
||||
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()
|
||||
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
|
||||
server_connection_successful = False
|
||||
try:
|
||||
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
|
||||
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)
|
||||
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 not server_connection_successful:
|
||||
self.status_label.config(text="Server unavailable\nLoading last playlist...")
|
||||
self.root.update()
|
||||
time.sleep(1)
|
||||
self.status_label.place_forget()
|
||||
self.load_fallback_playlist(fallback_playlist)
|
||||
|
||||
def load_fallback_playlist(self, fallback_playlist):
|
||||
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):
|
||||
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
|
||||
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):
|
||||
demo_images = []
|
||||
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 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:
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
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)
|
||||
if file_path.startswith('static/resurse/'):
|
||||
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}")
|
||||
self.log_event(file_name, "STARTED")
|
||||
self.cancel_timers()
|
||||
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}")
|
||||
self.auto_advance_timer = self.root.after(5000, self.next_media)
|
||||
|
||||
def play_video(self, file_path):
|
||||
self.status_label.place_forget()
|
||||
def run_vlc_subprocess():
|
||||
try:
|
||||
Logger.info(f"Starting system VLC subprocess for video: {file_path}")
|
||||
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):
|
||||
try:
|
||||
self.image_label.config(image=photo)
|
||||
self.image_label.image = photo
|
||||
except Exception as e:
|
||||
Logger.error(f"Error updating video frame: {e}")
|
||||
|
||||
def _show_video_error(self, error_msg):
|
||||
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):
|
||||
self.image_label.config(image='')
|
||||
self.status_label.config(text=text)
|
||||
self.auto_advance_timer = self.root.after(
|
||||
int(duration * 1000),
|
||||
self.next_media
|
||||
)
|
||||
|
||||
def show_image(self, file_path, duration):
|
||||
try:
|
||||
self.status_label.place_forget()
|
||||
self.status_label.config(text="")
|
||||
if PIL_AVAILABLE:
|
||||
img = Image.open(file_path)
|
||||
original_size = img.size
|
||||
screen_width = self.root.winfo_width()
|
||||
screen_height = self.root.winfo_height()
|
||||
if screen_width <= 1 or screen_height <= 1:
|
||||
screen_width = 1920
|
||||
screen_height = 1080
|
||||
final_img, offset = self.scale_image_to_screen(img, screen_width, screen_height, self.scaling_mode)
|
||||
photo = ImageTk.PhotoImage(final_img)
|
||||
self.image_label.config(image=photo)
|
||||
self.image_label.image = photo
|
||||
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:
|
||||
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")
|
||||
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):
|
||||
self.cancel_timers()
|
||||
if not self.playlist:
|
||||
return
|
||||
self.current_index = (self.current_index + 1) % len(self.playlist)
|
||||
if self.current_index == 0:
|
||||
threading.Thread(target=self.check_playlist_updates, daemon=True).start()
|
||||
self.play_current_media()
|
||||
|
||||
def previous_media(self):
|
||||
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):
|
||||
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")
|
||||
self.play_current_media()
|
||||
Logger.info(f"Media {'paused' if self.is_paused else 'resumed'}")
|
||||
|
||||
def cancel_timers(self):
|
||||
if self.auto_advance_timer:
|
||||
self.root.after_cancel(self.auto_advance_timer)
|
||||
self.auto_advance_timer = None
|
||||
|
||||
def show_controls(self):
|
||||
if self.control_frame:
|
||||
self.control_frame.place(relx=0.98, rely=0.98, anchor='se')
|
||||
|
||||
def hide_controls(self):
|
||||
if self.control_frame:
|
||||
self.control_frame.place_forget()
|
||||
|
||||
def schedule_hide_controls(self):
|
||||
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):
|
||||
self.show_controls()
|
||||
self.schedule_hide_controls()
|
||||
|
||||
def on_mouse_motion(self, event):
|
||||
self.show_controls()
|
||||
self.schedule_hide_controls()
|
||||
|
||||
def on_key_press(self, event):
|
||||
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:
|
||||
if key == 's':
|
||||
self.open_settings()
|
||||
self.show_controls()
|
||||
self.schedule_hide_controls()
|
||||
|
||||
def set_scaling_mode(self, mode):
|
||||
old_mode = self.scaling_mode
|
||||
self.scaling_mode = mode
|
||||
Logger.info(f"Scaling mode changed from '{old_mode}' to '{mode}'")
|
||||
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')
|
||||
self.root.after(2000, lambda: self.status_label.place_forget())
|
||||
if self.playlist and 0 <= self.current_index < len(self.playlist):
|
||||
self.cancel_timers()
|
||||
self.play_current_media()
|
||||
|
||||
def toggle_fullscreen(self):
|
||||
self.is_fullscreen = not self.is_fullscreen
|
||||
self.root.attributes('-fullscreen', self.is_fullscreen)
|
||||
|
||||
def open_settings(self):
|
||||
if hasattr(self, 'settings_window') and self.settings_window and self.settings_window.winfo_exists():
|
||||
self.settings_window.lift()
|
||||
return
|
||||
if not self.is_paused:
|
||||
self.toggle_play_pause()
|
||||
self.settings_window = SettingsWindow(self.root, self)
|
||||
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):
|
||||
try:
|
||||
config = load_config()
|
||||
quickconnect_key = config.get('quickconnect_key', '')
|
||||
except:
|
||||
quickconnect_key = ''
|
||||
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)
|
||||
self.center_dialog_on_screen(exit_dialog, 400, 200)
|
||||
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 = tk.Frame(exit_dialog, bg='#2d2d2d', padx=20, pady=20)
|
||||
content_frame.pack(fill=tk.BOTH, expand=True)
|
||||
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_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 = 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():
|
||||
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 = tk.Label(content_frame, text="", font=('Arial', 9),
|
||||
bg='#2d2d2d')
|
||||
error_label.pack()
|
||||
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)
|
||||
password_entry.bind('<Return>', lambda e: check_password())
|
||||
exit_dialog.bind('<Escape>', lambda e: cancel_exit())
|
||||
|
||||
def exit_application(self):
|
||||
Logger.info("Application exit requested")
|
||||
self.running = False
|
||||
self.root.quit()
|
||||
self.root.destroy()
|
||||
|
||||
def center_dialog_on_screen(self, dialog, width, height):
|
||||
dialog.update_idletasks()
|
||||
screen_width = dialog.winfo_screenwidth()
|
||||
screen_height = dialog.winfo_screenheight()
|
||||
center_x = int((screen_width - width) / 2)
|
||||
center_y = int((screen_height - height) / 2)
|
||||
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}")
|
||||
dialog.lift()
|
||||
dialog.focus_force()
|
||||
return center_x, center_y
|
||||
|
||||
def check_playlist_updates(self):
|
||||
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}")
|
||||
local_playlist_data = load_local_playlist()
|
||||
clean_unused_files(local_playlist_data.get('playlist', []))
|
||||
download_media_files(
|
||||
server_playlist_data.get('playlist', []),
|
||||
server_version
|
||||
)
|
||||
local_playlist_data = load_local_playlist()
|
||||
self.playlist = local_playlist_data.get('playlist', [])
|
||||
self.current_index = 0
|
||||
Logger.info("Playlist updated successfully")
|
||||
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):
|
||||
try:
|
||||
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
log_message = f"{timestamp} - {event}: {file_name}\n"
|
||||
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):
|
||||
def check_loop():
|
||||
while self.running:
|
||||
try:
|
||||
time.sleep(300)
|
||||
if self.running:
|
||||
self.check_playlist_updates()
|
||||
except Exception as e:
|
||||
Logger.error(f"Error in periodic check: {e}")
|
||||
threading.Thread(target=check_loop, daemon=True).start()
|
||||
|
||||
def run(self):
|
||||
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}")
|
||||
|
||||
|
||||
|
||||
@@ -193,4 +193,19 @@ def update_config_playlist_version(version):
|
||||
json.dump(config_data, file, indent=4)
|
||||
Logger.info(f"python_functions: Updated playlist version in app_config.txt to {version}.")
|
||||
except (IOError, json.JSONDecodeError) as e:
|
||||
Logger.error(f"python_functions: Failed to update playlist version in app_config.txt. Error: {e}")
|
||||
Logger.error(f"python_functions: Failed to update playlist version in app_config.txt. Error: {e}")
|
||||
|
||||
def check_for_new_server_playlist():
|
||||
"""Check if the server has a new playlist version compared to app_config.txt."""
|
||||
config = load_config()
|
||||
local_version = config.get('playlist_version', 0)
|
||||
server_data = fetch_server_playlist()
|
||||
server_version = server_data.get('version', 0)
|
||||
if server_version > local_version:
|
||||
print(f"A new playlist is available on the server: version {server_version} (local: {local_version})")
|
||||
Logger.info(f"A new playlist is available on the server: version {server_version} (local: {local_version})")
|
||||
return True
|
||||
else:
|
||||
print(f"No new playlist on the server. Local version: {local_version}, Server version: {server_version}")
|
||||
Logger.info(f"No new playlist on the server. Local version: {local_version}, Server version: {server_version}")
|
||||
return False
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
934
tkinter_app/src/tkinter_simple_player_old.py
Normal file
934
tkinter_app/src/tkinter_simple_player_old.py
Normal file
@@ -0,0 +1,934 @@
|
||||
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('<Key>', self.on_key_press)
|
||||
self.root.bind('<Button-1>', self.on_mouse_click)
|
||||
self.root.bind('<Motion>', 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("<Button-1>", on_press)
|
||||
button.bind("<ButtonRelease-1>", on_release)
|
||||
button.bind("<Enter>", on_enter)
|
||||
button.bind("<Leave>", 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('<Return>', lambda e: check_password())
|
||||
exit_dialog.bind('<Escape>', 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}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user