ypdated to check player playlist
@@ -1 +1 @@
|
||||
{"screen_orientation": "Landscape", "screen_name": "tv-panou1", "quickconnect_key": "8887779", "server_ip":"172.20.10.9", "port": "80"}
|
||||
{"screen_orientation": "Landscape", "screen_name": "tv-terasa", "quickconnect_key": "8887779", "server_ip": "digi-signage.moto-adv.com", "port": "80", "screen_w": "1920", "screen_h": "1080"}
|
||||
@@ -1,44 +1,13 @@
|
||||
2025-05-14 13:27:33 - STARTED: IMG_20250503_220547.jpg
|
||||
2025-05-14 13:27:36 - STARTED: IMG_20250506_080609.jpg
|
||||
2025-05-14 13:27:51 - STARTED: VID-20250502-WA0066.mp4
|
||||
2025-05-14 13:27:51 - STARTED: VID_20250502_113903.mp4
|
||||
2025-05-14 13:27:52 - STARTED: VID-20250503-WA0036.mp4
|
||||
2025-05-14 14:09:15 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:09:27 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:09:42 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:09:51 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:09:53 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:09:55 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:09:57 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:11:12 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:20:31 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:20:43 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:20:58 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:21:13 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:21:28 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:21:43 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:21:58 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:22:13 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:23:08 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:35:11 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:35:23 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:39:50 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:40:01 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:40:16 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:40:31 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:40:46 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:41:01 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:41:16 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:41:31 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:41:46 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:42:01 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:42:16 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:42:31 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:42:46 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:43:01 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:43:16 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:43:31 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:43:46 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-05-14 14:44:01 - STARTED: 03.03.2025_5S_Organigramm_Office-1.jpg
|
||||
2025-05-14 14:44:16 - STARTED: Operational_Plan_FY25-1.jpg
|
||||
2025-05-14 14:44:31 - STARTED: Office_audit_overview_5S-1.jpg
|
||||
2025-06-19 16:03:02 - STARTED: IMG-20250526-WA0003.jpg
|
||||
2025-06-19 16:03:03 - STARTED: IMG-20250602-WA0011.jpg
|
||||
2025-06-19 16:03:23 - STARTED: IMG_20250601_192845.jpg
|
||||
2025-06-19 16:03:43 - STARTED: IMG_20250601_185017.jpg
|
||||
2025-06-19 16:04:03 - STARTED: IMG_20250601_185019.jpg
|
||||
2025-06-19 16:04:23 - STARTED: IMG_20250601_180727.jpg
|
||||
2025-06-19 16:04:43 - STARTED: IMG_20250601_174724.jpg
|
||||
2025-06-19 16:05:03 - STARTED: IMG-20250531-WA0070.jpg
|
||||
2025-06-19 16:05:23 - STARTED: IMG-20250604-WA0006.jpg
|
||||
2025-06-19 16:05:43 - STARTED: IMG-20250526-WA0003.jpg
|
||||
2025-06-19 16:06:03 - STARTED: IMG-20250602-WA0011.jpg
|
||||
2025-06-19 16:06:23 - STARTED: IMG_20250601_192845.jpg
|
||||
2025-06-19 16:06:43 - STARTED: IMG_20250601_185017.jpg
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
Video:
|
||||
id: video_player
|
||||
allow_stretch: True
|
||||
keep_ratio: True
|
||||
size_hint: (1, 1)
|
||||
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
|
||||
opacity: 0
|
||||
@@ -79,7 +78,7 @@
|
||||
# Input fields in the upper half of the screen
|
||||
BoxLayout:
|
||||
orientation: 'vertical'
|
||||
size_hint_y: 0.2 # Allocate 60% of the screen height for input fields
|
||||
size_hint_y: 0.4 # Allocate 85% of the screen height for input fields
|
||||
|
||||
Label:
|
||||
text: "Screen Orientation"
|
||||
@@ -140,6 +139,28 @@
|
||||
multiline: False
|
||||
size_hint_y: None
|
||||
height: 40
|
||||
Label:
|
||||
text: "Screen Size Width / Height"
|
||||
size_hint_y: None
|
||||
height: 40
|
||||
|
||||
# New row for Screen Size Width / Height
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
size_hint_y: None
|
||||
height: 40
|
||||
spacing: 10
|
||||
TextInput:
|
||||
id: screen_width_input
|
||||
hint_text: "Width"
|
||||
multiline: False
|
||||
size_hint_x: 0.3
|
||||
|
||||
TextInput:
|
||||
id: screen_height_input
|
||||
hint_text: "Height"
|
||||
multiline: False
|
||||
size_hint_x: 0.3
|
||||
|
||||
# Buttons in the lower part of the screen
|
||||
BoxLayout:
|
||||
|
||||
@@ -47,6 +47,9 @@ class MediaPlayer(Screen):
|
||||
self.reset_timer = None # Timer to reset the button state after 3 minutes
|
||||
self.image_timer = None # Timer for scheduling the next media for images
|
||||
|
||||
# Load screen size from the configuration file
|
||||
self.load_screen_size()
|
||||
|
||||
# Schedule periodic updates to check for playlist updates
|
||||
Clock.schedule_interval(self.check_playlist_updates, 300) # Every 5 minutes
|
||||
# Bind key events to handle fullscreen toggle
|
||||
@@ -55,6 +58,21 @@ class MediaPlayer(Screen):
|
||||
# Start a timer to hide the buttons after 10 seconds
|
||||
self.hide_button_timer = Clock.schedule_once(self.hide_buttons, 10)
|
||||
|
||||
def load_screen_size(self):
|
||||
"""Load screen size from the configuration file and set the window size."""
|
||||
if os.path.exists(CONFIG_FILE):
|
||||
with open(CONFIG_FILE, 'r') as file:
|
||||
config_data = json.load(file)
|
||||
screen_w = config_data.get("screen_w", "1920")
|
||||
screen_h = config_data.get("screen_h", "1080")
|
||||
|
||||
# Set the window size
|
||||
try:
|
||||
Window.size = (int(screen_w), int(screen_h))
|
||||
Logger.info(f"Screen size set to {screen_w}x{screen_h}")
|
||||
except ValueError:
|
||||
Logger.error("Invalid screen size values in configuration file.")
|
||||
|
||||
def on_touch_down(self, touch):
|
||||
# Handle touch events to reset the button visibility.
|
||||
self.show_buttons() # Make all buttons visible
|
||||
@@ -83,12 +101,15 @@ class MediaPlayer(Screen):
|
||||
Window.fullscreen = not Window.fullscreen
|
||||
|
||||
def on_enter(self):
|
||||
# Called when the screen is entered.
|
||||
self.playlist = load_playlist() # Load the playlist
|
||||
download_media_files(self.playlist) # Download media files from the playlist
|
||||
clean_unused_files(self.playlist) # Remove unused files from the resource folder
|
||||
self.play_media() # Start playing media
|
||||
self.show_buttons() # Ensure buttons are visible when the screen is entered
|
||||
"""Called when the screen is entered."""
|
||||
self.playlist = load_playlist() # Load the playlist (local or server)
|
||||
if self.playlist: # Only proceed if the playlist is not empty
|
||||
download_media_files(self.playlist) # Download media files if the playlist has changed
|
||||
clean_unused_files(self.playlist) # Remove unused files from the resource folder
|
||||
self.play_media() # Start playing media
|
||||
self.show_buttons() # Ensure buttons are visible when the screen is entered
|
||||
else:
|
||||
Logger.warning("MediaPlayer: Playlist is empty. No media to play.")
|
||||
|
||||
def log_event(self, file_name, event):
|
||||
# Log the start or stop event of a media file and clean up old logs.
|
||||
@@ -325,7 +346,9 @@ class SettingsScreen(Screen):
|
||||
"screen_name": "",
|
||||
"quickconnect_key": "",
|
||||
"server_ip": "",
|
||||
"port": "" # Default port
|
||||
"port": "",
|
||||
"screen_w": "", # Default width
|
||||
"screen_h": "" # Default height
|
||||
}
|
||||
|
||||
def save_config(self):
|
||||
@@ -335,6 +358,8 @@ class SettingsScreen(Screen):
|
||||
self.config_data["quickconnect_key"] = self.ids.quickconnect_key_input.text
|
||||
self.config_data["server_ip"] = self.ids.server_ip_input.text
|
||||
self.config_data["port"] = self.ids.port_input.text
|
||||
self.config_data["screen_w"] = self.ids.screen_width_input.text
|
||||
self.config_data["screen_h"] = self.ids.screen_height_input.text
|
||||
|
||||
with open(CONFIG_FILE, 'w') as file:
|
||||
json.dump(self.config_data, file)
|
||||
@@ -350,6 +375,8 @@ class SettingsScreen(Screen):
|
||||
self.ids.quickconnect_key_input.text = self.config_data.get("quickconnect_key", "")
|
||||
self.ids.server_ip_input.text = self.config_data.get("server_ip", "")
|
||||
self.ids.port_input.text = self.config_data.get("port", "8080")
|
||||
self.ids.screen_width_input.text = self.config_data.get("screen_w", "")
|
||||
self.ids.screen_height_input.text = self.config_data.get("screen_h", "")
|
||||
|
||||
def show_exit_popup(self):
|
||||
# Create the popup layout
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import requests
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
from kivy.logger import Logger
|
||||
|
||||
CONFIG_FILE = './Resurse/app_config.txt'
|
||||
|
||||
LOCAL_PLAYLIST_FILE = './static/local_playlist.json' # Path to the local playlist file
|
||||
def load_config():
|
||||
"""Load configuration from app_config.txt."""
|
||||
if os.path.exists(CONFIG_FILE):
|
||||
@@ -46,6 +46,7 @@ else:
|
||||
Logger.info(f"python_functions: Configuration loaded: server={server}, host={host}, quick={quick}, port={port}")
|
||||
Logger.info(f"python_functions: Configuration status: {config_status}")
|
||||
|
||||
|
||||
def load_playlist():
|
||||
"""Load playlist from the server or local storage."""
|
||||
try:
|
||||
@@ -66,17 +67,53 @@ def load_playlist():
|
||||
if response.status_code == 200:
|
||||
try:
|
||||
# Parse the JSON response
|
||||
playlist = response.json().get('playlist', [])
|
||||
Logger.info("python_functions: Playlist loaded successfully.")
|
||||
Logger.debug(f"python_functions: Loaded playlist: {playlist}")
|
||||
return playlist
|
||||
server_data = response.json()
|
||||
playlist = server_data.get('playlist', [])
|
||||
|
||||
# Validate the playlist structure
|
||||
if isinstance(playlist, list) and all(isinstance(item, dict) for item in playlist):
|
||||
Logger.info("python_functions: Playlist loaded successfully.")
|
||||
Logger.debug(f"python_functions: Loaded playlist: {playlist}")
|
||||
|
||||
# Save the playlist locally
|
||||
with open(LOCAL_PLAYLIST_FILE, 'w') as local_file:
|
||||
json.dump(playlist, local_file)
|
||||
Logger.info("python_functions: Updated local playlist with server data.")
|
||||
|
||||
return playlist
|
||||
else:
|
||||
Logger.error("python_functions: Invalid playlist structure from server.")
|
||||
except json.JSONDecodeError as e:
|
||||
Logger.error(f"python_functions: Failed to parse JSON response: {e}")
|
||||
else:
|
||||
Logger.error(f"python_functions: Failed to retrieve playlist: {response.text}")
|
||||
Logger.error(f"python_functions: Failed to retrieve playlist. Status Code: {response.status_code}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
Logger.error(f"python_functions: Failed to load playlist: {e}")
|
||||
return []
|
||||
|
||||
# Fallback to local playlist
|
||||
return load_local_playlist()
|
||||
|
||||
|
||||
def load_local_playlist():
|
||||
"""Load the playlist from local storage."""
|
||||
if os.path.exists(LOCAL_PLAYLIST_FILE):
|
||||
try:
|
||||
with open(LOCAL_PLAYLIST_FILE, 'r') as local_file:
|
||||
local_playlist = json.load(local_file)
|
||||
|
||||
# Validate the structure of the local playlist
|
||||
if isinstance(local_playlist, list) and all(isinstance(item, dict) for item in local_playlist):
|
||||
Logger.info("python_functions: Loaded and validated local playlist.")
|
||||
return local_playlist
|
||||
else:
|
||||
Logger.error("python_functions: Invalid local playlist structure.")
|
||||
return []
|
||||
except json.JSONDecodeError:
|
||||
Logger.error("python_functions: Failed to parse local playlist file.")
|
||||
return []
|
||||
else:
|
||||
Logger.warning("python_functions: Local playlist file not found.")
|
||||
return []
|
||||
|
||||
def download_media_files(playlist):
|
||||
"""Download media files from the playlist."""
|
||||
|
||||
1
src/static/local_playlist.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"duration": 20, "file_name": "IMG-20250526-WA0003.jpg", "url": "http://digi-signage.moto-adv.com/media/IMG-20250526-WA0003.jpg"}, {"duration": 20, "file_name": "IMG-20250602-WA0011.jpg", "url": "http://digi-signage.moto-adv.com/media/IMG-20250602-WA0011.jpg"}, {"duration": 20, "file_name": "IMG_20250601_192845.jpg", "url": "http://digi-signage.moto-adv.com/media/IMG_20250601_192845.jpg"}, {"duration": 20, "file_name": "IMG_20250601_185017.jpg", "url": "http://digi-signage.moto-adv.com/media/IMG_20250601_185017.jpg"}, {"duration": 20, "file_name": "IMG_20250601_185019.jpg", "url": "http://digi-signage.moto-adv.com/media/IMG_20250601_185019.jpg"}, {"duration": 20, "file_name": "IMG_20250601_180727.jpg", "url": "http://digi-signage.moto-adv.com/media/IMG_20250601_180727.jpg"}, {"duration": 20, "file_name": "IMG_20250601_174724.jpg", "url": "http://digi-signage.moto-adv.com/media/IMG_20250601_174724.jpg"}, {"duration": 20, "file_name": "IMG-20250531-WA0070.jpg", "url": "http://digi-signage.moto-adv.com/media/IMG-20250531-WA0070.jpg"}, {"duration": 20, "file_name": "IMG-20250604-WA0006.jpg", "url": "http://digi-signage.moto-adv.com/media/IMG-20250604-WA0006.jpg"}]
|
||||
|
Before Width: | Height: | Size: 2.2 MiB |
BIN
src/static/resurse/IMG-20250526-WA0003.jpg
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
src/static/resurse/IMG-20250531-WA0070.jpg
Normal file
|
After Width: | Height: | Size: 842 KiB |
BIN
src/static/resurse/IMG-20250602-WA0011.jpg
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
src/static/resurse/IMG-20250604-WA0006.jpg
Normal file
|
After Width: | Height: | Size: 637 KiB |
BIN
src/static/resurse/IMG_20250601_174724.jpg
Normal file
|
After Width: | Height: | Size: 8.8 MiB |
BIN
src/static/resurse/IMG_20250601_180727.jpg
Normal file
|
After Width: | Height: | Size: 10 MiB |
BIN
src/static/resurse/IMG_20250601_185017.jpg
Normal file
|
After Width: | Height: | Size: 8.2 MiB |
BIN
src/static/resurse/IMG_20250601_185019.jpg
Normal file
|
After Width: | Height: | Size: 7.2 MiB |
BIN
src/static/resurse/IMG_20250601_192845.jpg
Normal file
|
After Width: | Height: | Size: 10 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |