Update scripts/config_manager.py
All checks were successful
Generate M3U Playlist with Auto-Organization / build-and-organize (push) Successful in 1m39s
All checks were successful
Generate M3U Playlist with Auto-Organization / build-and-organize (push) Successful in 1m39s
This commit is contained in:
parent
e50ea51d1d
commit
1d99776ac9
1 changed files with 154 additions and 118 deletions
|
@ -1,5 +1,6 @@
|
|||
"""
|
||||
Configuration Manager - Handles all configuration loading and management
|
||||
Pure country-based detection with enhanced patterns
|
||||
"""
|
||||
|
||||
import json
|
||||
|
@ -8,7 +9,7 @@ import logging
|
|||
from pathlib import Path
|
||||
|
||||
class ConfigManager:
|
||||
"""Centralized configuration management."""
|
||||
"""Centralized configuration management for pure country-based organization."""
|
||||
|
||||
def __init__(self, config_dir="config"):
|
||||
self.config_dir = Path(config_dir)
|
||||
|
@ -20,17 +21,18 @@ class ConfigManager:
|
|||
self.import_file = "bulk_import.m3u"
|
||||
self.log_file = "playlist_update.log"
|
||||
|
||||
# Config files
|
||||
# Config files (removed group_overrides)
|
||||
self.settings_file = self.config_dir / "settings.json"
|
||||
self.patterns_file = self.config_dir / "patterns.json"
|
||||
self.group_overrides_file = self.config_dir / "group_overrides.json"
|
||||
|
||||
# Load configurations
|
||||
self.settings = self._load_settings()
|
||||
self.patterns = self._load_patterns()
|
||||
self.group_overrides = self._load_group_overrides()
|
||||
|
||||
logging.info("Configuration manager initialized")
|
||||
# No group overrides - pure country detection
|
||||
self.group_overrides = {}
|
||||
|
||||
logging.info("Configuration manager initialized (Pure Country Mode)")
|
||||
|
||||
def _load_settings(self):
|
||||
"""Load settings with comprehensive defaults."""
|
||||
|
@ -50,7 +52,12 @@ class ConfigManager:
|
|||
"max_backups": 5,
|
||||
"log_level": "INFO",
|
||||
"clear_import_after_processing": True,
|
||||
"delete_import_file": False
|
||||
"delete_import_file": False,
|
||||
# Enhanced country detection settings
|
||||
"pure_country_mode": True,
|
||||
"prefer_country_over_category": True,
|
||||
"enable_prefix_detection": True,
|
||||
"enable_quality_tags": True
|
||||
}
|
||||
|
||||
if self.settings_file.exists():
|
||||
|
@ -71,132 +78,161 @@ class ConfigManager:
|
|||
return defaults
|
||||
|
||||
def _load_patterns(self):
|
||||
"""Load country detection patterns from external config."""
|
||||
default_patterns = {
|
||||
"""Load enhanced country detection patterns from external config."""
|
||||
# This will be the fallback if patterns.json doesn't exist
|
||||
minimal_patterns = {
|
||||
"country_patterns": {
|
||||
"🇺🇸 United States": ["cbs", "nbc", "abc", "fox", "espn", "cnn", "hbo", " usa", " us ", ".us", "america", "nfl"],
|
||||
"🇬🇧 United Kingdom": ["bbc", "itv", "sky", "channel 4", "e4", " uk", ".uk", "british", "premier league"],
|
||||
"🇨🇦 Canada": ["cbc", "ctv", "global", "canada", "canadian", " ca ", ".ca"],
|
||||
"🇩🇪 Germany": ["ard", "zdf", "rtl", "sat.1", "pro7", "germany", "german", " de ", ".de"],
|
||||
"🇫🇷 France": ["tf1", "france 2", "m6", "canal+", "france", "french", " fr ", ".fr"],
|
||||
"🇪🇸 Spain": ["tve", "antena 3", "telecinco", "spain", "spanish", " es ", ".es"],
|
||||
"🇮🇹 Italy": ["rai", "mediaset", "canale 5", "italy", "italian", " it ", ".it"],
|
||||
"🇳🇱 Netherlands": ["npo", "rtl nl", "netherlands", "dutch", "holland", " nl ", ".nl"],
|
||||
"🇧🇪 Belgium": ["vtm", "één", "canvas", "belgium", "belgian", " be ", ".be"],
|
||||
"🇨🇭 Switzerland": ["srf", "rts", "switzerland", "swiss", " ch ", ".ch"],
|
||||
"🇦🇹 Austria": ["orf", "austria", "austrian", " at ", ".at"],
|
||||
"🇵🇹 Portugal": ["rtp", "sic", "tvi", "portugal", "portuguese", " pt ", ".pt"],
|
||||
"🇮🇪 Ireland": ["rte", "tg4", "ireland", "irish", " ie ", ".ie"],
|
||||
"🇸🇪 Sweden": ["svt", "tv4", "sweden", "swedish", " se ", ".se"],
|
||||
"🇳🇴 Norway": ["nrk", "tv 2 no", "norway", "norwegian", " no ", ".no"],
|
||||
"🇩🇰 Denmark": ["dr", "tv2 dk", "denmark", "danish", " dk ", ".dk"],
|
||||
"🇫🇮 Finland": ["yle", "mtv3", "finland", "finnish", " fi ", ".fi"],
|
||||
"🇮🇸 Iceland": ["ruv", "iceland", "icelandic", " is ", ".is"],
|
||||
"🇷🇺 Russia": ["channel one", "rossiya", "ntv", "russia", "russian", " ru ", ".ru"],
|
||||
"🇵🇱 Poland": ["tvp", "polsat", "tvn", "poland", "polish", " pl ", ".pl"],
|
||||
"🇨🇿 Czech Republic": ["ct", "nova", "prima", "czech", " cz ", ".cz"],
|
||||
"🇸🇰 Slovakia": ["rtvs", "markiza", "slovakia", "slovak", " sk ", ".sk"],
|
||||
"🇭🇺 Hungary": ["mtv hu", "rtl klub", "hungary", "hungarian", " hu ", ".hu"],
|
||||
"🇺🇦 Ukraine": ["1+1", "inter", "ictv", "ukraine", "ukrainian", " ua ", ".ua"],
|
||||
"🇷🇴 Romania": ["tvr", "pro tv", "romania", "romanian", " ro ", ".ro"],
|
||||
"🇧🇬 Bulgaria": ["btv", "nova bg", "bulgaria", "bulgarian", " bg ", ".bg"],
|
||||
"🇭🇷 Croatia": ["hrt", "nova tv hr", "croatia", "croatian", " hr ", ".hr"],
|
||||
"🇷🇸 Serbia": ["rts", "pink", "serbia", "serbian", " rs ", ".rs"],
|
||||
"🇬🇷 Greece": ["ert", "mega gr", "greece", "greek", " gr ", ".gr"],
|
||||
"🇧🇷 Brazil": ["globo", "band", "sbt", "brazil", "brasil", " br ", ".br"],
|
||||
"🇦🇷 Argentina": ["telefe", "canal 13", "argentina", " ar ", ".ar"],
|
||||
"🇲🇽 Mexico": ["televisa", "tv azteca", "mexico", "méxico", " mx ", ".mx"],
|
||||
"🇨🇱 Chile": ["tvn", "mega", "chile", "chilean", " cl ", ".cl"],
|
||||
"🇨🇴 Colombia": ["caracol", "rcn", "colombia", "colombian", " co ", ".co"],
|
||||
"🇵🇪 Peru": ["america tv pe", "peru", "peruvian", " pe ", ".pe"],
|
||||
"🇻🇪 Venezuela": ["venevision", "venezuela", "venezuelan", " ve ", ".ve"],
|
||||
"🇨🇳 China": ["cctv", "phoenix", "china", "chinese", " cn ", ".cn"],
|
||||
"🇯🇵 Japan": ["nhk", "fuji", "tv asahi", "japan", "japanese", " jp ", ".jp"],
|
||||
"🇰🇷 South Korea": ["kbs", "sbs kr", "mbc kr", "korea", "korean", " kr ", ".kr"],
|
||||
"🇰🇵 North Korea": ["kctv", "north korea", "dprk"],
|
||||
"🇹🇼 Taiwan": ["cts", "ctv", "tvbs", "taiwan", "taiwanese", " tw ", ".tw"],
|
||||
"🇭🇰 Hong Kong": ["tvb", "atv", "hong kong", "hongkong", " hk ", ".hk"],
|
||||
"🇹🇭 Thailand": ["ch3", "ch7", "thai pbs", "thailand", "thai", " th ", ".th"],
|
||||
"🇻🇳 Vietnam": ["vtv", "htv", "vietnam", "vietnamese", " vn ", ".vn"],
|
||||
"🇮🇩 Indonesia": ["tvri", "sctv", "rcti", "indonesia", "indonesian", " id ", ".id"],
|
||||
"🇲🇾 Malaysia": ["tv1", "tv3", "astro", "malaysia", "malaysian", " my ", ".my", "my:"],
|
||||
"🇸🇬 Singapore": ["channel 5", "channel 8", "singapore", " sg ", ".sg"],
|
||||
"🇵🇭 Philippines": ["abs-cbn", "gma", "philippines", "filipino", " ph ", ".ph"],
|
||||
"🇮🇳 India": ["star plus", "zee tv", "colors", "sony tv", "india", "indian", "hindi", " in ", ".in"],
|
||||
"🇵🇰 Pakistan": ["ptv", "geo tv", "ary", "pakistan", "pakistani", " pk ", ".pk"],
|
||||
"🇧🇩 Bangladesh": ["btv", "channel i", "bangladesh", "bangladeshi", " bd ", ".bd"],
|
||||
"🇱🇰 Sri Lanka": ["rupavahini", "sirasa", "sri lanka", " lk ", ".lk"],
|
||||
"🇳🇵 Nepal": ["nepal tv", "kantipur", "nepal", "nepali", " np ", ".np"],
|
||||
"🇦🇫 Afghanistan": ["rta", "tolo tv", "afghanistan", "afghan", " af ", ".af"],
|
||||
"🇦🇺 Australia": ["abc au", "seven", "nine", "ten", "australia", "australian", "aussie", " au ", ".au"],
|
||||
"🇳🇿 New Zealand": ["tvnz", "tvnz 1", "tvnz 2", "three nz", "tvnz duke", "new zealand", "kiwi", " nz ", ".nz"],
|
||||
"🇸🇦 Arabic": ["al jazeera", "mbc", "lbc", "dubai tv", "arabic", "arab", "qatar", "dubai", "saudi"],
|
||||
"🇮🇱 Israel": ["kan", "keshet 12", "israel", "israeli", "hebrew", " il ", ".il"],
|
||||
"🇹🇷 Turkey": ["trt", "atv", "kanal d", "turkey", "turkish", " tr ", ".tr", "tr |"],
|
||||
"🇮🇷 Iran": ["irib", "press tv", "iran", "iranian", "persian", " ir ", ".ir"],
|
||||
"🇪🇬 Egypt": ["nile tv", "cbc egypt", "egypt", "egyptian", " eg ", ".eg"],
|
||||
"🇿🇦 South Africa": ["sabc", "etv", "mnet", "south africa", " za ", ".za"],
|
||||
"🇳🇬 Nigeria": ["nta", "channels tv", "nigeria", "nigerian", " ng ", ".ng"]
|
||||
"🇺🇸 United States": ["cbs", "nbc", "abc", "fox", "espn", "cnn", "hbo", "usa", "america", "nfl"],
|
||||
"🇬🇧 United Kingdom": ["bbc", "itv", "sky", "channel 4", "e4", "uk", "british", "premier league"],
|
||||
"🇨🇦 Canada": ["cbc", "ctv", "global", "canada", "canadian"],
|
||||
"🇩🇪 Germany": ["ard", "zdf", "rtl", "sat.1", "pro7", "germany", "german"],
|
||||
"🇫🇷 France": ["tf1", "france 2", "m6", "canal+", "france", "french"],
|
||||
"🇪🇸 Spain": ["tve", "antena 3", "telecinco", "spain", "spanish"],
|
||||
"🇮🇹 Italy": ["rai", "mediaset", "canale 5", "italy", "italian"],
|
||||
"🇳🇱 Netherlands": ["npo", "rtl nl", "netherlands", "dutch", "holland"],
|
||||
"🇧🇷 Brazil": ["globo", "band", "sbt", "brazil", "brasil"],
|
||||
"🇦🇷 Argentina": ["telefe", "canal 13", "argentina"],
|
||||
"🇲🇽 Mexico": ["televisa", "tv azteca", "mexico", "méxico"],
|
||||
"🇦🇺 Australia": ["abc au", "seven", "nine", "ten", "australia", "australian"],
|
||||
"🇸🇦 Arabic": ["al jazeera", "mbc", "lbc", "dubai tv", "arabic", "arab"]
|
||||
},
|
||||
"country_prefixes": {
|
||||
"🇺🇦 Ukraine": ["ua |"],
|
||||
"🇵🇱 Poland": ["pl |"],
|
||||
"🇹🇷 Turkey": ["tr |"],
|
||||
"🇲🇾 Malaysia": ["my:", "my |"],
|
||||
"🇬🇧 United Kingdom": ["uk:", "uk |"],
|
||||
"🇺🇸 United States": ["us:", "us |"]
|
||||
"🇺🇸 United States": ["us:", "us |", "usa:"],
|
||||
"🇬🇧 United Kingdom": ["uk:", "uk |", "gb:"],
|
||||
"🇩🇪 Germany": ["de:", "de |", "ger:"],
|
||||
"🇫🇷 France": ["fr:", "fr |", "france:"],
|
||||
"🇪🇸 Spain": ["es:", "es |", "spain:"],
|
||||
"🇮🇹 Italy": ["it:", "it |", "italy:"],
|
||||
"🇺🇦 Ukraine": ["ua:", "ua |", "ukraine:"],
|
||||
"🇵🇱 Poland": ["pl:", "pl |", "poland:"],
|
||||
"🇹🇷 Turkey": ["tr:", "tr |", "turkey:"],
|
||||
"🇲🇾 Malaysia": ["my:", "my |", "malaysia:"],
|
||||
"🇦🇺 Australia": ["au:", "au |", "australia:"],
|
||||
"🇨🇦 Canada": ["ca:", "ca |", "canada:"]
|
||||
},
|
||||
"quality_patterns": {
|
||||
"4K": ["4k", "uhd", "2160p"],
|
||||
"FHD": ["fhd", "1080p", "1080"],
|
||||
"HD": ["hd", "720p", "720"],
|
||||
"SD": ["sd", "480p", "360p"]
|
||||
"4K": ["4k", "uhd", "2160p", "ultra hd"],
|
||||
"FHD": ["fhd", "1080p", "1080", "full hd"],
|
||||
"HD": ["hd", "720p", "720", "high definition"],
|
||||
"SD": ["sd", "480p", "360p", "standard"]
|
||||
},
|
||||
"adult_keywords": ["xxx", "adult", "porn", "sex", "erotic", "playboy", "18+"]
|
||||
"adult_keywords": [
|
||||
"xxx", "adult", "porn", "sex", "erotic", "playboy", "18+",
|
||||
"nude", "naked", "sexy", "babes"
|
||||
]
|
||||
}
|
||||
|
||||
if self.patterns_file.exists():
|
||||
try:
|
||||
with open(self.patterns_file, 'r', encoding='utf-8') as f:
|
||||
user_patterns = json.load(f)
|
||||
# Deep merge with defaults
|
||||
for category, patterns in user_patterns.items():
|
||||
if category in default_patterns:
|
||||
if isinstance(default_patterns[category], dict):
|
||||
default_patterns[category].update(patterns)
|
||||
else:
|
||||
default_patterns[category] = patterns
|
||||
else:
|
||||
default_patterns[category] = patterns
|
||||
logging.info(f"Loaded user patterns from {self.patterns_file}")
|
||||
logging.info(f"Loaded enhanced patterns from {self.patterns_file}")
|
||||
|
||||
# Validate that required sections exist
|
||||
required_sections = ["country_patterns", "country_prefixes", "quality_patterns", "adult_keywords"]
|
||||
for section in required_sections:
|
||||
if section not in user_patterns:
|
||||
logging.warning(f"Missing section '{section}' in patterns file, using minimal fallback")
|
||||
user_patterns[section] = minimal_patterns.get(section, {})
|
||||
|
||||
return user_patterns
|
||||
except (json.JSONDecodeError, IOError) as e:
|
||||
logging.warning(f"Could not load patterns, using defaults: {e}")
|
||||
logging.warning(f"Could not load patterns, using minimal patterns: {e}")
|
||||
else:
|
||||
# Create default patterns file for user customization
|
||||
# Create minimal patterns file (user should update with enhanced version)
|
||||
with open(self.patterns_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(default_patterns, f, indent=2, ensure_ascii=False)
|
||||
logging.info(f"Created default patterns file: {self.patterns_file}")
|
||||
json.dump(minimal_patterns, f, indent=2, ensure_ascii=False)
|
||||
logging.info(f"Created minimal patterns file: {self.patterns_file}")
|
||||
logging.info("Update patterns.json with enhanced version for better detection")
|
||||
|
||||
return default_patterns
|
||||
return minimal_patterns
|
||||
|
||||
def _load_group_overrides(self):
|
||||
"""Load group overrides."""
|
||||
if self.group_overrides_file.exists():
|
||||
try:
|
||||
with open(self.group_overrides_file, 'r', encoding='utf-8') as f:
|
||||
overrides = json.load(f)
|
||||
logging.info(f"Loaded {len(overrides)} group overrides")
|
||||
return overrides
|
||||
except (json.JSONDecodeError, IOError) as e:
|
||||
logging.warning(f"Could not load group overrides: {e}")
|
||||
def get_country_detection_stats(self):
|
||||
"""Get statistics about country detection capabilities."""
|
||||
stats = {
|
||||
'total_countries': len(self.patterns.get('country_patterns', {})),
|
||||
'total_prefixes': len(self.patterns.get('country_prefixes', {})),
|
||||
'total_patterns': 0,
|
||||
'quality_levels': len(self.patterns.get('quality_patterns', {})),
|
||||
'adult_keywords': len(self.patterns.get('adult_keywords', [])),
|
||||
'pure_country_mode': True
|
||||
}
|
||||
|
||||
# Count total detection patterns
|
||||
for country, patterns in self.patterns.get('country_patterns', {}).items():
|
||||
stats['total_patterns'] += len(patterns)
|
||||
|
||||
return stats
|
||||
|
||||
def validate_patterns(self):
|
||||
"""Validate pattern configuration and return any issues."""
|
||||
issues = []
|
||||
|
||||
# Check for required sections
|
||||
required_sections = ['country_patterns', 'country_prefixes', 'quality_patterns', 'adult_keywords']
|
||||
for section in required_sections:
|
||||
if section not in self.patterns:
|
||||
issues.append(f"Missing required section: {section}")
|
||||
|
||||
# Check for empty country patterns
|
||||
country_patterns = self.patterns.get('country_patterns', {})
|
||||
if not country_patterns:
|
||||
issues.append("No country patterns defined")
|
||||
else:
|
||||
# Create empty overrides file as example
|
||||
example_overrides = {
|
||||
"example_keyword": "🇺🇸 United States",
|
||||
"another_keyword": "🇬🇧 United Kingdom"
|
||||
}
|
||||
with open(self.group_overrides_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(example_overrides, f, indent=2, ensure_ascii=False)
|
||||
logging.info(f"Created example group overrides file: {self.group_overrides_file}")
|
||||
for country, patterns in country_patterns.items():
|
||||
if not patterns or not isinstance(patterns, list):
|
||||
issues.append(f"Invalid or empty patterns for country: {country}")
|
||||
|
||||
return {}
|
||||
# Check for duplicate patterns across countries
|
||||
all_patterns = []
|
||||
for country, patterns in country_patterns.items():
|
||||
for pattern in patterns:
|
||||
if pattern in all_patterns:
|
||||
issues.append(f"Duplicate pattern '{pattern}' found in multiple countries")
|
||||
all_patterns.append(pattern)
|
||||
|
||||
return issues
|
||||
|
||||
def get_countries_list(self):
|
||||
"""Get a list of all supported countries."""
|
||||
return list(self.patterns.get('country_patterns', {}).keys())
|
||||
|
||||
def save_settings(self):
|
||||
"""Save current settings to file."""
|
||||
try:
|
||||
with open(self.settings_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(self.settings, f, indent=2)
|
||||
logging.info("Settings saved successfully")
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error(f"Could not save settings: {e}")
|
||||
return False
|
||||
|
||||
def update_setting(self, key, value):
|
||||
"""Update a specific setting."""
|
||||
self.settings[key] = value
|
||||
logging.info(f"Updated setting: {key} = {value}")
|
||||
|
||||
def is_pure_country_mode(self):
|
||||
"""Check if pure country mode is enabled."""
|
||||
return self.settings.get('pure_country_mode', True)
|
||||
|
||||
def get_detection_summary(self):
|
||||
"""Get a summary of detection capabilities for logging."""
|
||||
stats = self.get_country_detection_stats()
|
||||
return (f"Country Detection: {stats['total_countries']} countries, "
|
||||
f"{stats['total_patterns']} patterns, "
|
||||
f"{stats['total_prefixes']} prefixes, "
|
||||
f"Mode: Pure Country")
|
||||
|
||||
def cleanup_old_config_files(self):
|
||||
"""Remove old group overrides file if it exists."""
|
||||
old_overrides_file = self.config_dir / "group_overrides.json"
|
||||
if old_overrides_file.exists():
|
||||
try:
|
||||
old_overrides_file.unlink()
|
||||
logging.info("Removed obsolete group_overrides.json file")
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.warning(f"Could not remove old group_overrides.json: {e}")
|
||||
return False
|
Loading…
Add table
Add a link
Reference in a new issue