Browse Source

08/21/2025

master
melancholytron 4 months ago
parent
commit
655107a566
  1. 69
      terminalTv.py

69
terminalTv.py

@ -3,6 +3,7 @@ import os
import re import re
import subprocess import subprocess
import sys import sys
import json
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from datetime import datetime, timedelta from datetime import datetime, timedelta
from urllib.request import urlopen, Request from urllib.request import urlopen, Request
@ -11,27 +12,53 @@ from urllib.error import URLError
import threading import threading
import time import time
# Configuration
# Load configuration from JSON file
try:
with open('config.json') as config_file:
config = json.load(config_file)
M3U_URL = config.get('m3u_url', "http://10.0.0.17:8409/iptv/channels.m3u")
XMLTV_URL = config.get('xmltv_url', "http://10.0.0.17:8409/iptv/xmltv.xml")
USER_AGENT = config.get('user_agent', "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
UPDATE_INTERVAL = config.get('update_interval', 900)
MONITOR = config.get('monitor', None)
# Base MPV command with monitor options if specified
MPV_BASE = ["mpv"]
if MONITOR is not None:
MPV_BASE.extend(["--fs", f"--fs-screen={MONITOR}"])
MPV_BASE.extend(config.get('mpv_options', [
"--really-quiet",
"--no-terminal",
"--force-window=immediate"
]))
except FileNotFoundError:
print("Configuration file not found, using default settings")
M3U_URL = "http://10.0.0.17:8409/iptv/channels.m3u" M3U_URL = "http://10.0.0.17:8409/iptv/channels.m3u"
XMLTV_URL = "http://10.0.0.17:8409/iptv/xmltv.xml" XMLTV_URL = "http://10.0.0.17:8409/iptv/xmltv.xml"
MPV_COMMAND = ["mpv", "--really-quiet", "--no-terminal", "--force-window=immediate"]
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
UPDATE_INTERVAL = 900 # 15 minutes in seconds
UPDATE_INTERVAL = 900
MONITOR = None
MPV_BASE = [
"mpv",
"--really-quiet",
"--no-terminal",
"--force-window=immediate"
]
# Color Palette
# Color Palette remains the same
PALETTE = [ PALETTE = [
('header', 'white', 'dark blue'), ('header', 'white', 'dark blue'),
('footer', 'white', 'dark blue'), ('footer', 'white', 'dark blue'),
('channel', 'black', 'light gray'),
('channel', 'black', 'light cyan'),
('channel_focus', 'white', 'dark blue'), ('channel_focus', 'white', 'dark blue'),
('program_now', 'white', 'dark green'), ('program_now', 'white', 'dark green'),
('program_next', 'black', 'light gray'), ('program_next', 'black', 'light gray'),
('error', 'white', 'dark red'), ('error', 'white', 'dark red'),
('divider', 'light gray', ''),
('program_desc', 'light cyan', ''), # New color for descriptions
('time', 'yellow', ''), # New color for time displays
('title', 'bold', ''), # New color for titles
('update', 'light green', ''), # Color for update notifications
('divider', 'dark green', ''),
('program_desc', 'light cyan', ''),
('time', 'yellow', ''),
('title', 'bold', ''),
('update', 'light blue', ''),
] ]
# ASCII Art # ASCII Art
@ -235,7 +262,8 @@ class IPTVPlayer:
self.program_listbox = urwid.ListBox(self.program_walker) self.program_listbox = urwid.ListBox(self.program_walker)
# Add update time to footer # Add update time to footer
self.footer_text = urwid.Text("Q: Quit | ↑↓: Navigate | Enter: Play Channel | L: Reload | Last update: Loading...", align='center')
monitor_info = f" | Monitor: {MONITOR}" if MONITOR is not None else ""
self.footer_text = urwid.Text(f"Q: Quit | ↑↓: Navigate | Enter: Play Channel | L: Reload | Last update: Loading...{monitor_info}", align='center')
self.footer = urwid.AttrMap(self.footer_text, 'footer') self.footer = urwid.AttrMap(self.footer_text, 'footer')
program_frame = urwid.Frame( program_frame = urwid.Frame(
@ -276,7 +304,8 @@ class IPTVPlayer:
def update_footer(self): def update_footer(self):
"""Update footer with last update time""" """Update footer with last update time"""
time_str = self.last_update.strftime("%H:%M:%S") time_str = self.last_update.strftime("%H:%M:%S")
self.footer_text.set_text(f"Q: Quit | ↑↓: Navigate | Enter: Play Channel | L: Reload | Last update: {time_str}")
monitor_info = f" | Monitor: {MONITOR}" if MONITOR is not None else ""
self.footer_text.set_text(f"Q: Quit | ↑↓: Navigate | Enter: Play Channel | L: Reload | Last update: {time_str}{monitor_info}")
def start_update_thread(self): def start_update_thread(self):
"""Start background thread for periodic updates""" """Start background thread for periodic updates"""
@ -359,7 +388,7 @@ class IPTVPlayer:
info = [] info = []
max_line_length = 60 # Define this at the top so it's available everywhere max_line_length = 60 # Define this at the top so it's available everywhere
info.append([("header", f"📺 Channel: {channel['name']}")])
info.append([("header", f"--Channel: {channel['name']}")])
if channel.get('group'): if channel.get('group'):
info.append([("title", f"Group: {channel['group']}")]) info.append([("title", f"Group: {channel['group']}")])
@ -372,7 +401,7 @@ class IPTVPlayer:
# Current show section with colorful formatting # Current show section with colorful formatting
info.append([]) # Empty line info.append([]) # Empty line
info.append([("program_now", "NOW PLAYING")])
info.append([("program_now", "--NOW PLAYING")])
info.append([("title", f"Title: {channel['current_show']['title']}")]) info.append([("title", f"Title: {channel['current_show']['title']}")])
info.append([ info.append([
("time", f"Time: {start_time} - {end_time} "), ("time", f"Time: {start_time} - {end_time} "),
@ -381,7 +410,7 @@ class IPTVPlayer:
if channel['current_show']['desc']: if channel['current_show']['desc']:
info.append([]) # Empty line info.append([]) # Empty line
info.append([("program_desc", "📝 Description:")])
info.append([("program_desc", "--Description:")])
# Split long description into multiple lines # Split long description into multiple lines
desc = channel['current_show']['desc'] desc = channel['current_show']['desc']
for i in range(0, len(desc), max_line_length): for i in range(0, len(desc), max_line_length):
@ -395,13 +424,13 @@ class IPTVPlayer:
info.append([]) # Empty line info.append([]) # Empty line
info.append([("divider", "" * 50)]) info.append([("divider", "" * 50)])
info.append([]) # Empty line info.append([]) # Empty line
info.append([("program_next", "UP NEXT")])
info.append([("program_next", "--UP NEXT")])
info.append([("title", f"Title: {channel['next_show']['title']}")]) info.append([("title", f"Title: {channel['next_show']['title']}")])
info.append([("time", f"Time: {next_start} - {next_end}")]) info.append([("time", f"Time: {next_start} - {next_end}")])
if channel['next_show']['desc']: if channel['next_show']['desc']:
info.append([]) # Empty line info.append([]) # Empty line
info.append([("program_desc", "📝 Description:")])
info.append([("program_desc", "--Description:")])
desc = channel['next_show']['desc'] desc = channel['next_show']['desc']
# Limit description to 5 lines to prevent overflow # Limit description to 5 lines to prevent overflow
max_lines = 5 max_lines = 5
@ -419,13 +448,13 @@ class IPTVPlayer:
next_end = channel['next_show']['stop'].strftime("%H:%M") next_end = channel['next_show']['stop'].strftime("%H:%M")
info.append([]) # Empty line info.append([]) # Empty line
info.append([("program_next", "UP NEXT")])
info.append([("program_next", "--UP NEXT")])
info.append([("title", f"Title: {channel['next_show']['title']}")]) info.append([("title", f"Title: {channel['next_show']['title']}")])
info.append([("time", f"Time: {next_start} - {next_end}")]) info.append([("time", f"Time: {next_start} - {next_end}")])
if channel['next_show']['desc']: if channel['next_show']['desc']:
info.append([]) # Empty line info.append([]) # Empty line
info.append([("program_desc", "📝 Description:")])
info.append([("program_desc", "--Description:")])
desc = channel['next_show']['desc'] desc = channel['next_show']['desc']
# Limit description to 5 lines to prevent overflow # Limit description to 5 lines to prevent overflow
max_lines = 5 max_lines = 5
@ -447,7 +476,7 @@ class IPTVPlayer:
self.mpv_process.wait() self.mpv_process.wait()
try: try:
self.mpv_process = subprocess.Popen(MPV_COMMAND + [url])
self.mpv_process = subprocess.Popen(MPV_BASE + [url])
except Exception as e: except Exception as e:
# Create proper widget for error message # Create proper widget for error message
self.program_walker[:] = [urwid.Text([("error", f"Failed to play stream: {str(e)}")])] self.program_walker[:] = [urwid.Text([("error", f"Failed to play stream: {str(e)}")])]

Loading…
Cancel
Save