shvchenko commited on
Commit
f8d987c
Β·
verified Β·
1 Parent(s): 30b734e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -23
app.py CHANGED
@@ -5,23 +5,23 @@ import re
5
  import json
6
  from difflib import get_close_matches
7
 
8
- # Load channel mapping JSON
9
  with open("channels_fixed.json", "r", encoding="utf-8") as f:
10
  channel_map = json.load(f)
11
 
12
- # Random 3-character filename generator
13
  def random_filename(uppercase=True):
14
  letters = string.ascii_uppercase if uppercase else string.ascii_lowercase
15
  return "".join(random.choice(letters) for _ in range(3)) + ".m3u"
16
 
17
- # Insert tvg-id immediately after #EXTINF:-1
18
  def insert_tvg_id(extinf_line, tvg_id):
19
- line = re.sub(r'tvg-id="[^"]*"', '', extinf_line) # remove existing
20
  line = line.replace('#EXTINF:-1', f'#EXTINF:-1 tvg-id="{tvg_id}"', 1)
21
  line = re.sub(r'\s+', ' ', line).strip()
22
  return line
23
 
24
- # Apply special event rules
25
  def apply_event_special_cases(extinf_line, channel_name):
26
  line = extinf_line
27
  if "MLB LEAGUE PASS" in channel_name:
@@ -34,14 +34,23 @@ def apply_event_special_cases(extinf_line, channel_name):
34
  return insert_tvg_id(line, "Live.Event.us")
35
  return line
36
 
37
- # Main processor
 
 
 
 
 
 
 
 
 
38
  def process_m3u(m3u_text):
39
  lines = m3u_text.splitlines()
40
  out_247_blocks = []
41
  out_events_blocks = []
42
  log = []
43
 
44
- # Hardcoded abbreviation + forced fixes
45
  hardcoded_fixes = {
46
  "BTN": "Big.Ten.Network.HD.us2",
47
  "SNY": "SNY.SportsNet.New.York.HD.us2",
@@ -50,6 +59,7 @@ def process_m3u(m3u_text):
50
  "MSG": "MSG.National.us2",
51
  "REELZ USA": "ReelzChannel.HD.us2",
52
  "ABCNY USA": "ABC.(WABC).New.York,.NY.us",
 
53
  "OWN USA": "Oprah.Winfrey.Network.HD.us2",
54
  "DISCOVERY USA": "Discovery.Channel.ca2",
55
  "OUTDOOR CHANNEL": "Outdoor.Channel.HD.us2",
@@ -57,12 +67,15 @@ def process_m3u(m3u_text):
57
  "LOITV": "Soccer.Dummy.us",
58
  }
59
 
 
 
 
60
  for i, line in enumerate(lines):
61
  if line.startswith("#EXTINF"):
62
  url = lines[i+1] if i+1 < len(lines) else ""
63
  extinf = line
64
 
65
- # Extract tvg-id and channel name
66
  tvg_match = re.search(r'tvg-id="([^"]*)"', extinf)
67
  tvg_id = tvg_match.group(1) if tvg_match else None
68
  name_match = re.search(r",(.*)", extinf)
@@ -83,49 +96,71 @@ def process_m3u(m3u_text):
83
 
84
  # --- EVENTS ---
85
  elif group_title and "EVENTS" in group_title:
86
- candidate = channel_name
 
 
 
 
 
 
 
 
87
 
88
- # Check hardcoded fixes first
89
  matched_fix = False
90
- for key, fixed_id in hardcoded_fixes.items():
91
- if candidate.upper().startswith(key.upper()):
 
 
92
  new_ext = insert_tvg_id(extinf, fixed_id)
93
- new_ext = apply_event_special_cases(new_ext, candidate)
94
  out_events_blocks.append((new_ext, url))
95
- log.append(f"βœ… EVENTS | {candidate} β†’ {fixed_id} (hardcoded)")
96
  matched_fix = True
97
- break
 
 
 
 
 
 
 
 
 
 
 
98
  if matched_fix:
99
  continue
100
 
101
- # Try matching against JSON
102
  match = None
103
  for key, data in channel_map.items():
104
- if data.get("tvg_id") and key.lower() in candidate.lower():
105
  match = data["tvg_id"]
106
  break
107
  if not match:
108
  keys = list(channel_map.keys())
109
- guesses = get_close_matches(candidate, keys, n=1, cutoff=0.6)
110
  if guesses:
111
  match = channel_map[guesses[0]].get("tvg_id")
 
112
  if match:
113
  new_ext = insert_tvg_id(extinf, match)
114
- log.append(f"βœ… EVENTS | {candidate} β†’ {match}")
115
  else:
116
  new_ext = insert_tvg_id(extinf, "Live.Event.us")
117
- log.append(f"⚠️ EVENTS | {candidate} β†’ Live.Event.us (fallback)")
118
 
119
- new_ext = apply_event_special_cases(new_ext, candidate)
120
  out_events_blocks.append((new_ext, url))
121
 
122
- # Build output playlists
123
  out_247 = "\n".join([f"{ext}\n{url}" for ext, url in out_247_blocks])
124
  out_events = "\n".join([f"{ext}\n{url}" for ext, url in out_events_blocks])
125
 
126
  return out_247, out_events, "\n".join(log)
127
 
128
- # Gradio UI with better panel sizing
129
  def run_app(m3u_text):
130
  out_247, out_events, log = process_m3u(m3u_text)
131
  file_247 = random_filename(uppercase=True)
 
5
  import json
6
  from difflib import get_close_matches
7
 
8
+ # Load channel mapping JSON (unchanged)
9
  with open("channels_fixed.json", "r", encoding="utf-8") as f:
10
  channel_map = json.load(f)
11
 
12
+ # Random 3-character filename generator (unchanged)
13
  def random_filename(uppercase=True):
14
  letters = string.ascii_uppercase if uppercase else string.ascii_lowercase
15
  return "".join(random.choice(letters) for _ in range(3)) + ".m3u"
16
 
17
+ # Insert tvg-id immediately after #EXTINF:-1 (unchanged)
18
  def insert_tvg_id(extinf_line, tvg_id):
19
+ line = re.sub(r'tvg-id="[^"]*"', '', extinf_line) # remove existing tvg-id if present
20
  line = line.replace('#EXTINF:-1', f'#EXTINF:-1 tvg-id="{tvg_id}"', 1)
21
  line = re.sub(r'\s+', ' ', line).strip()
22
  return line
23
 
24
+ # Apply special event rules (unchanged)
25
  def apply_event_special_cases(extinf_line, channel_name):
26
  line = extinf_line
27
  if "MLB LEAGUE PASS" in channel_name:
 
34
  return insert_tvg_id(line, "Live.Event.us")
35
  return line
36
 
37
+ # Normalize helper: remove non-alphanum, lowercase
38
+ def normalize_name(s: str) -> str:
39
+ if not s:
40
+ return ""
41
+ s = s.upper()
42
+ # Remove punctuation but keep letters and digits
43
+ s = re.sub(r'[^A-Z0-9]', '', s)
44
+ return s
45
+
46
+ # Main processor (Project 1 Base with minimal fix)
47
  def process_m3u(m3u_text):
48
  lines = m3u_text.splitlines()
49
  out_247_blocks = []
50
  out_events_blocks = []
51
  log = []
52
 
53
+ # Hardcoded abbreviation + forced fixes (now includes your new entries)
54
  hardcoded_fixes = {
55
  "BTN": "Big.Ten.Network.HD.us2",
56
  "SNY": "SNY.SportsNet.New.York.HD.us2",
 
59
  "MSG": "MSG.National.us2",
60
  "REELZ USA": "ReelzChannel.HD.us2",
61
  "ABCNY USA": "ABC.(WABC).New.York,.NY.us",
62
+ "ABC NY USA": "ABC.(WABC).New.York,.NY.us", # handle space variant
63
  "OWN USA": "Oprah.Winfrey.Network.HD.us2",
64
  "DISCOVERY USA": "Discovery.Channel.ca2",
65
  "OUTDOOR CHANNEL": "Outdoor.Channel.HD.us2",
 
67
  "LOITV": "Soccer.Dummy.us",
68
  }
69
 
70
+ # Precompute normalized hardcoded map for fast comparisons
71
+ normalized_hardcoded = {normalize_name(k): v for k, v in hardcoded_fixes.items()}
72
+
73
  for i, line in enumerate(lines):
74
  if line.startswith("#EXTINF"):
75
  url = lines[i+1] if i+1 < len(lines) else ""
76
  extinf = line
77
 
78
+ # Extract tvg-id and channel name (same as base)
79
  tvg_match = re.search(r'tvg-id="([^"]*)"', extinf)
80
  tvg_id = tvg_match.group(1) if tvg_match else None
81
  name_match = re.search(r",(.*)", extinf)
 
96
 
97
  # --- EVENTS ---
98
  elif group_title and "EVENTS" in group_title:
99
+ # candidate extraction: prefer bracketed network name if present
100
+ bracket_match = re.search(r'\[([^\]]+)\]', channel_name)
101
+ if bracket_match:
102
+ candidate_raw = bracket_match.group(1).strip()
103
+ else:
104
+ # fallback to entire display string
105
+ candidate_raw = channel_name
106
+
107
+ candidate_norm = normalize_name(candidate_raw)
108
 
109
+ # 1) Check hardcoded fixes FIRST using normalized keys
110
  matched_fix = False
111
+ if candidate_norm:
112
+ # exact normalized match
113
+ if candidate_norm in normalized_hardcoded:
114
+ fixed_id = normalized_hardcoded[candidate_norm]
115
  new_ext = insert_tvg_id(extinf, fixed_id)
116
+ new_ext = apply_event_special_cases(new_ext, candidate_raw)
117
  out_events_blocks.append((new_ext, url))
118
+ log.append(f"βœ… EVENTS | {candidate_raw} β†’ {fixed_id} (hardcoded exact)")
119
  matched_fix = True
120
+ else:
121
+ # sometimes bracket may be abbreviation (e.g. BTN), so check startswith any key
122
+ for key_norm, fixed_id in normalized_hardcoded.items():
123
+ # if candidate begins with the key (normalized), or key appears within candidate_norm
124
+ if candidate_norm.startswith(key_norm) or key_norm in candidate_norm:
125
+ new_ext = insert_tvg_id(extinf, fixed_id)
126
+ new_ext = apply_event_special_cases(new_ext, candidate_raw)
127
+ out_events_blocks.append((new_ext, url))
128
+ log.append(f"βœ… EVENTS | {candidate_raw} β†’ {fixed_id} (hardcoded partial)")
129
+ matched_fix = True
130
+ break
131
+
132
  if matched_fix:
133
  continue
134
 
135
+ # 2) Try matching against JSON (same behavior as base)
136
  match = None
137
  for key, data in channel_map.items():
138
+ if data.get("tvg_id") and key.lower() in candidate_raw.lower():
139
  match = data["tvg_id"]
140
  break
141
  if not match:
142
  keys = list(channel_map.keys())
143
+ guesses = get_close_matches(candidate_raw, keys, n=1, cutoff=0.6)
144
  if guesses:
145
  match = channel_map[guesses[0]].get("tvg_id")
146
+
147
  if match:
148
  new_ext = insert_tvg_id(extinf, match)
149
+ log.append(f"βœ… EVENTS | {candidate_raw} β†’ {match}")
150
  else:
151
  new_ext = insert_tvg_id(extinf, "Live.Event.us")
152
+ log.append(f"⚠️ EVENTS | {candidate_raw} β†’ Live.Event.us (fallback)")
153
 
154
+ new_ext = apply_event_special_cases(new_ext, candidate_raw)
155
  out_events_blocks.append((new_ext, url))
156
 
157
+ # Build output playlists (unchanged formatting)
158
  out_247 = "\n".join([f"{ext}\n{url}" for ext, url in out_247_blocks])
159
  out_events = "\n".join([f"{ext}\n{url}" for ext, url in out_events_blocks])
160
 
161
  return out_247, out_events, "\n".join(log)
162
 
163
+ # Gradio UI with requested sizing (small input, larger log)
164
  def run_app(m3u_text):
165
  out_247, out_events, log = process_m3u(m3u_text)
166
  file_247 = random_filename(uppercase=True)