#!/usr/bin/env python3 """ Self-hosted IPTV: serves M3U playlists that schedule video files from /movies and /series with randomized order so the same show never appears twice in a row. """ import logging import os from iptv.config import ( CHANNELS_FILE, EPG_TIMESPAN_DAYS, SCHEDULE_CACHE_TTL_SEC, NORMALIZE_LIVE_STREAM, NORMALIZE_TARGET_RES, init_epg_timespan, ) from iptv.cache import CacheManager from iptv.channel import ChannelRepository from iptv.schedule import ScheduleBuilder from iptv.tmdb_client import TMDBClient from iptv.metadata_prefetcher import MetadataPrefetcher from iptv.epg_builder import EPGBuilder from iptv.server import create_server logger = logging.getLogger(__name__) def main(): init_epg_timespan() log_level = getattr(logging, os.environ.get("LOG_LEVEL", "INFO").upper(), logging.INFO) logging.basicConfig( level=log_level, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) if not CHANNELS_FILE.exists(): print(f"Warning: {CHANNELS_FILE} not found. Create it from data/channels.json.example") logger.info( "EPG timespan: %s days, schedule refresh after: %.1f h", EPG_TIMESPAN_DAYS, SCHEDULE_CACHE_TTL_SEC / 3600, ) if NORMALIZE_LIVE_STREAM: logger.info( "Live stream normalization enabled (target: %s) — prevents crashes when switching episodes", NORMALIZE_TARGET_RES, ) channel_repo = ChannelRepository() schedule_builder = ScheduleBuilder() schedule_builder.set_channel_repo(channel_repo) cache_manager = CacheManager(schedule_builder=schedule_builder) schedule_builder.set_cache_manager(cache_manager) if not cache_manager._ensure_cache_dir(): logger.warning( "Cannot create cache dir %s — schedule will rebuild on every restart. " "Ensure /data is mounted read-write (not :ro).", cache_manager._cache_dir, ) tmdb_client = TMDBClient() prefetcher = MetadataPrefetcher(schedule_builder, tmdb_client, channel_repo) prefetcher.start() epg_builder = EPGBuilder( schedule_builder, tmdb_client, channel_repo, cache_manager, prefetcher ) port = 8080 server = create_server( channel_repo=channel_repo, schedule_builder=schedule_builder, epg_builder=epg_builder, host="0.0.0.0", port=port, cache_manager=cache_manager, ) print(f"Serving at http://0.0.0.0:{port}/ (playlist: http://:{port}/playlist.m3u)") server.serve_forever() if __name__ == "__main__": main()